home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / comm2 / xbtx.lha / Source / BTXService.cpp < prev    next >
C/C++ Source or Header  |  1995-12-03  |  66KB  |  3,062 lines

  1. /*
  2. **    $Id: BTXService.cpp 1.6 1995/12/03 12:16:23 olsen Exp olsen $
  3. **
  4. **    :ts=4
  5. */
  6.  
  7. /*
  8.  * Amiga changes copyright © 1995 by Olaf Barthel, All Rights Reserved
  9.  *
  10.  * Copyright (c) 1992, 1993 Arno Augustin, Frank Hoering, University of
  11.  * Erlangen-Nuremberg, Germany.
  12.  * All rights reserved.
  13.  *
  14.  * Redistribution and use in source and binary forms, with or without
  15.  * modification, are permitted provided that the following conditions
  16.  * are met:
  17.  * 1. Redistributions of source code must retain the above copyright
  18.  *    notice, this list of conditions and the following disclaimer.
  19.  * 2. Redistributions in binary form must reproduce the above copyright
  20.  *    notice, this list of conditions and the following disclaimer in the
  21.  *    documentation and/or other materials provided with the distribution.
  22.  * 3. All advertising materials mentioning features or use of this software
  23.  *    must display the following acknowledgement:
  24.  *      This product includes software developed by the University of
  25.  *      Erlangen-Nuremberg, Germany.
  26.  * 4. Neither the name of the University nor the names of its contributors
  27.  *    may be used to endorse or promote products derived from this software
  28.  *    without specific prior written permission.
  29.  *
  30.  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
  31.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  32.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
  33.  * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  34.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  35.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  36.  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  37.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  38.  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  39.  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  40.  *
  41.  * This software has not been validated by the ``Bundesamt fuer Zulassungen in
  42.  * der Telekommunikation'' of the ``Deutsche Bundepost Telekom'' and thus
  43.  * must not be used for accessing the BTX-Network of the Telekom in Germany.
  44.  *
  45.  * Diese Software hat keine Zulassung durch das Bundesamt fuer Zulassungen in
  46.  * der Telekommunikation der Deutschen Bundespost Telekom und darf daher nicht
  47.  * am Netz der Deutschen Bundespost Telekom in Deutschland betrieben werden.
  48.  */
  49.  
  50. //#define USE_PROTOCOL
  51.  
  52. /****************************************************************************/
  53.  
  54. #include <string.h>
  55. #include <ctype.h>
  56.  
  57. /****************************************************************************/
  58.  
  59. #ifndef _BTXSERVICE_HPP
  60. #include "BTXService.hpp"
  61. #endif
  62.  
  63. /****************************************************************************/
  64.  
  65. #define D(x)
  66.  
  67. /****************************************************************************/
  68.  
  69. BTXService::~BTXService()
  70. {
  71.     Close();
  72. }
  73.  
  74. BTXService::BTXService()
  75. {
  76.     memset(screen,0,sizeof(screen));
  77.     memset(&t,0,sizeof(t));
  78.     memset(&backup,0,sizeof(backup));
  79.     memset(data,0,sizeof(data));
  80.  
  81.     rows = fontheight = reachedEOF = 0;
  82.     pushback = 0;
  83.  
  84.     telefile = NULL;
  85.     teledownload = FALSE;
  86.     telename[0] = 0;
  87.     telemode = MODE_Unknown;
  88.  
  89.     transparent_max = 0;
  90.  
  91.     reveal = TRUE;
  92.  
  93.     restartLen = continueLen = 0;
  94.     is_fif = FALSE;
  95.  
  96. #ifdef USE_PROTOCOL
  97.     protocolfile = NULL;
  98. #endif
  99. }
  100.  
  101. VOID BTXService::Close(VOID)
  102. {
  103.     if(telefile)
  104.     {
  105.         fclose(telefile);
  106.         telefile = NULL;
  107.     }
  108.  
  109.     is_fif = FALSE;
  110.  
  111. #ifdef USE_PROTOCOL
  112.     if(protocolfile)
  113.     {
  114.         fclose(protocolfile);
  115.         protocolfile = NULL;
  116.     }
  117. #endif
  118. }
  119.  
  120. LONG BTXService::Open(BTXDisplay *Disp,Application *Appl)
  121. {
  122.     AppDisplay    = Disp;
  123.     App            = Appl;
  124.  
  125.     Disp->MonitorData(&rows,&fontheight);
  126.  
  127. #ifdef USE_PROTOCOL
  128.     protocolfile = fopen("t:protocol","wb");
  129. #endif
  130.  
  131.     init_layer6();
  132.     return(0);
  133. }
  134.  
  135. int BTXService::ProcessInput(VOID)
  136. {
  137.     return(process_BTX_data());
  138. }
  139.  
  140. UBYTE BTXService::ConvertChar(int c,int s,int d)
  141. {
  142.    static UBYTE supp_map[96] =
  143.       { ' ', 0xa1, 0xa2, 0xa3, '$', 0xa5, '#', 0xa7, 0xa4, '`', '\"', 0xab,
  144.     0, 0, 0, 0, 0xb0, 0xb1, 0xb2, 0xb3, 0xd7, 0xb5, 0xb6, 0xb7, 0xf7,
  145.     '\'', '\"', 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0, 0x60, 0x27, 0, '~',
  146.     0xaf, 0, 0, 0x22, 0x22, 0xb0, 0, 0, 0x22, 0xb8, 0, 0xad, 0xb9, 0xae,
  147.     0xa9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc6, 0, 0, 0, 0, 0,
  148.     0, 0, 0xd8, 0, 0, 0xfe, 0, 0, 0, 0, 0xe6, 0, 0, 0, 0, 0, 0, 0, 0xf8,
  149.     0, 0xdf, 0xde, 0, 0, 0 };
  150.  
  151.    static UBYTE diacritical_map[26*2][16] = {
  152.     { 0, 0xc0, 0xc1, 0xc2, 0xc3, 0, 0, 0, 0xc4, 0xc4, 0xc5, 0, 0, 0xc4, 0, 0 },
  153.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },     /* B */
  154.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0 },
  155.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },  /* D */
  156.     { 0, 0xc8, 0xc9, 0xca, 0, 0, 0, 0, 0xcb, 0xcb, 0, 0, 0, 0xcb, 0, 0 },
  157.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  158.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  159.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },  /* H */
  160.     { 0, 0xcc, 0xcd, 0xce, 0, 0, 0, 0, 0xcf, 0xcf, 0, 0, 0, 0xcf, 0, 0 },
  161.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  162.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  163.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  164.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  165.     { 0, 0, 0, 0, 0xd1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },  /* N */
  166.     { 0, 0xd2, 0xd3, 0xd4, 0xd5, 0, 0, 0, 0xd6, 0xd6, 0, 0, 0, 0xd6, 0, 0 },
  167.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  168.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  169.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  170.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  171.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* T */
  172.     { 0, 0xd9, 0xda, 0xdb, 0, 0, 0, 0, 0xdc, 0xdc, 0, 0, 0, 0xdc, 0, 0 },
  173.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  174.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  175.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* X */
  176.     { 0, 0, 0xdd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  177.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  178.     { 0, 0xe0, 0xe1, 0xe2, 0xe3, 0, 0, 0, 0xe4, 0xe4, 0xe5, 0, 0, 0xe4, 0, 0 },
  179.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  180.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xe7, 0, 0, 0, 0 },  /* c */
  181.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  182.     { 0, 0xe8, 0xe9, 0xea, 0, 0, 0, 0, 0xeb, 0xeb, 0, 0, 0, 0xeb, 0, 0 },
  183.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  184.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  185.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* h */
  186.     { 0, 0xec, 0xed, 0xee, 0, 0, 0, 0, 0xef, 0xef, 0, 0, 0, 0xef, 0, 0 },
  187.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  188.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  189.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  190.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  191.     { 0, 0, 0, 0, 0xf1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* n */
  192.     { 0, 0xf2, 0xf3, 0xf4, 0xf5, 0, 0, 0, 0xf6, 0xf6, 0, 0, 0, 0xf6, 0, 0 },
  193.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  194.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  195.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  196.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  197.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* t */
  198.     { 0, 0xf9, 0xfa, 0xfb, 0, 0, 0, 0, 0xfc, 0xfc, 0, 0, 0, 0xfc, 0, 0 },
  199.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  200.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  201.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  202.     { 0, 0, 0xfd, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0xff, 0, 0 },  /* y */
  203.     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
  204.  
  205.     UBYTE Char;
  206.  
  207.     /* ASCII out of  1st supplementary set of mosaic characters */
  208.     if(s==SUP1 && c>=0x40 && c<=0x5f)
  209.         Char = (UBYTE)c;
  210.     else
  211.         Char = (UBYTE)' ';
  212.  
  213.     /* supplementary set of graphic characters */
  214.     if(s==SUPP && supp_map[c-0x20])
  215.         Char = (UBYTE)supp_map[c-0x20];
  216.     else
  217.     {
  218.         /* composed characters, diacritical marks (page 123) */
  219.         if(s==PRIM)
  220.         {
  221.             if(!d)
  222.                 Char = (UBYTE)c;  /* ASCII character */
  223.             else
  224.             {
  225.                 if(d>=0x40 && d<=0x4f)
  226.                 {
  227.                     if(c>=0x41 && c<=0x5a && diacritical_map[c-0x41][d&0xf])
  228.                         Char = (UBYTE)diacritical_map[c-0x41][d&0xf];
  229.                     else
  230.                     {
  231.                         if(c>=0x61 && c<=0x7a && diacritical_map[c-0x61+26][d&0xf])
  232.                             Char = (UBYTE)diacritical_map[c-0x61+26][d&0xf];
  233.                     }
  234.                 }
  235.             }
  236.         }
  237.     }
  238.  
  239.     return(Char);
  240. }
  241.  
  242. VOID BTXService::GetMatrix(UBYTE *Matrix,int *CursorX,int *CursorY)
  243. {
  244.     if(Matrix)
  245.     {
  246.         int x,y;
  247.  
  248.         memset(Matrix,' ',40 * 24);
  249.  
  250.         for(y = 0 ; y < rows ; y++)
  251.         {
  252.             for(x = 0 ; x < 40 ; x++)
  253.                 Matrix[y * 40 + x] = ConvertChar(screen[y][x].chr & 0x7f,screen[y][x].set,(screen[y][x].chr>>8) & 0x7f);
  254.         }
  255.     }
  256.  
  257.     if(CursorX)
  258.     {
  259.         if(t.cursor_on)
  260.             *CursorX = t.cursorx;
  261.         else
  262.             *CursorX = -1;
  263.     }
  264.  
  265.     if(CursorY)
  266.     {
  267.         if(t.cursor_on)
  268.             *CursorY = t.cursory;
  269.         else
  270.             *CursorY = -1;
  271.     }
  272. }
  273.  
  274. VOID BTXService::ToggleReveal(VOID)
  275. {
  276.     reveal ^= TRUE;
  277.     redraw_screen_rect(0, 0, 39, rows-1);
  278. }
  279.  
  280. /******************************************************************************/
  281.  
  282. /* all 'page' references refer to 'FTZ 157 D2 E' */
  283.  
  284. #include "Control.h"
  285. #include "Font.h"
  286. #include "Attributes.h"
  287.  
  288. /*
  289.  * initialize layer6 variables
  290.  */
  291. void BTXService::init_layer6()
  292. {
  293.    int y;
  294.  
  295.    fontheight = 10;
  296.    rows = 24;
  297.    t.cursorx = t.cursory = 1;
  298.    t.wrap = 1;
  299.    t.service_break = 0;
  300.    t.scroll_area = 0;
  301.    t.scroll_impl = 1;
  302.    t.cursor_on = 0;
  303.    t.par_attr = 0;
  304.    t.par_fg = WHITE;
  305.    t.par_bg = TRANSPARENT;
  306.    for(y=0; y<24; y++)    AppDisplay->define_fullrow_bg(y, BLACK);
  307.    clearscreen();
  308.    default_sets();
  309. }
  310.  
  311. /*
  312.  * Read and process one layer6 code sequence.
  313.  * Returns 1 when DCT (terminate data collect 0x1a) is received, else 0.
  314.  */
  315.  
  316. int BTXService::process_BTX_data()
  317. {
  318.     int set, c1, c2, dct=0;
  319.  
  320.     c1 = layer2getc();
  321.  
  322.     if(c1>=0x00 && c1<=0x1f)
  323.         dct = primary_control_C0(c1);
  324.     else
  325.     {
  326.         if(c1>=0x80 && c1<=0x9f)
  327.             supplementary_control_C1(c1, 0);
  328.         else
  329.         {
  330.             if(t.sshift)
  331.                 set = t.G0123L[ t.sshift ];
  332.             else
  333.                 set = t.G0123L[ t.leftright[ (c1&0x80) >> 7 ] ];
  334.  
  335.             if( set == SUPP  &&  (c1 & 0x70) == 0x40 )     /* diacritical ??? */
  336.             {
  337.                 D(printf("diacritical mark %d\n", c1 & 0x0f));
  338.  
  339.                 c2 = layer2getc();
  340.  
  341.                 if(reachedEOF)
  342.                     return(-1);
  343.  
  344.                 if(c2&0x60)
  345.                     c1 = (c1<<8) | c2;
  346.  
  347.                 t.sshift = 0;
  348.             }
  349.  
  350.             D(printf("OUTPUT 0x%02x '%c'\n", c1&0xff, isprint(c1&0xff) ? c1&0xff : '.'));
  351.  
  352.             output(c1);
  353.  
  354.             t.lastchar = c1;
  355.         }
  356.     }
  357.  
  358.     if(reachedEOF)
  359.         return(-1);
  360.  
  361.         // This is to assure proper data flow whilst doing a FIF
  362.         // transfer
  363.  
  364.     if(dct && is_fif)
  365.     {
  366.         int x,y,j;
  367.         char mark[8];
  368.  
  369.         for(x = 40-5, y = rows-1, j = 0 ; x < 40 ; x++)
  370.             mark[j++] = (char)ConvertChar(screen[y][x].chr & 0x7f,screen[y][x].set,(screen[y][x].chr>>8) & 0x7f);
  371.  
  372.         mark[j] = 0;
  373.  
  374.             // Prompts to continue transparent data transmission
  375.  
  376.         if(!strcmp(mark,"SH399") || !strcmp(mark,"SH400"))
  377.             App->AppChannel->PutChar('1');    // Continue with transmission
  378.     }
  379.  
  380.     return dct;
  381. }
  382.  
  383.  
  384. /*
  385.  * get one byte from protocol layer 2.
  386.  */
  387.  
  388. int BTXService::layer2getc()
  389. {
  390.     LONG Value;
  391.     int c;
  392.  
  393.     // Are there any characters pushed back?
  394.     if(pushback > 0)
  395.     {
  396.         Value = App->DispatchDisplayEvent();
  397.  
  398.         if(Value == CHANNELERR_EOF)
  399.             reachedEOF = 1;
  400.  
  401.         c = pushedback[--pushback];
  402.     }
  403.     else
  404.     {
  405.         while(!reachedEOF)
  406.         {
  407.             Value = App->DispatchEvent();
  408.  
  409.             switch(Value)
  410.             {
  411.                 case CHANNELERR_EOF:
  412.  
  413.                     reachedEOF = 1;
  414.                     return(US);
  415.  
  416.                 case CHANNELERR_Timeout:
  417.                 case CHANNELERR_Nothing:
  418.  
  419.                     App->WaitEvent();
  420.                     continue;
  421.             }
  422.  
  423.             if(Value < 0)
  424.                 reachedEOF = 1;
  425.             else
  426.             {
  427.                 c = (int)Value;
  428.  
  429. #ifdef USE_PROTOCOL
  430.                 if(protocolfile)
  431.                     fputc(c,protocolfile);
  432. #endif
  433.             }
  434.  
  435.             break;
  436.         }
  437.  
  438.         if(reachedEOF)
  439.             c = US;
  440.     }
  441.  
  442.     D(printf("(%c %03x %2d/%2d %2x/%2x) (0x%02x)   ", t.serialmode ? 'S' : 'P',
  443.         t.serialmode ? screen[t.cursory-1][t.cursorx-1].attr : t.par_attr,
  444.         t.cursory, t.cursorx,
  445.         t.serialmode ? screen[t.cursory-1][t.cursorx-1].fg : t.par_fg,
  446.         t.serialmode ? screen[t.cursory-1][t.cursorx-1].bg : t.par_bg, c));
  447.  
  448.     return c;
  449. }
  450.  
  451.  
  452. // unget character 'c'. Up to four characters can be pushed back
  453. void BTXService::layer2ungetc(int c)
  454. {
  455.     if(pushback < 4)
  456.     {
  457.         pushedback[pushback++] = (UBYTE)c;
  458.         D(printf("<-- character pushed back\n"));
  459.     }
  460.     else
  461.         D(fprintf(stderr,"XBTX: internal error: ungetc-buffer overflow !\n"));
  462. }
  463.  
  464.  
  465. /*
  466.  * initialize default character sets (page 113)
  467.  */
  468. void BTXService::default_sets()
  469. {
  470.    t.G0123L[G0] = PRIM;
  471.    t.G0123L[G1] = SUP2;
  472.    t.G0123L[G2] = SUPP;
  473.    t.G0123L[G3] = SUP3;
  474.    t.G0123L[ L] = L;       /* always L !!! (cannot be changed) */
  475.    t.leftright[0] = G0;
  476.    t.leftright[1] = G2;
  477.    t.sshift = 0;
  478.    t.save_left = G0;
  479.    t.prim = G0;
  480.    t.supp = G2;
  481. }
  482.  
  483. /*
  484.  * move the cursor, perform automatic wraparound (page 97)
  485.  *                    and implicite scrolling (page 101)
  486.  */
  487. void BTXService::move_cursor(int cmd, int y, int x)
  488. {
  489.    int up=0, down=0;
  490.  
  491.    /* erase old cursor */
  492.    if(t.cursor_on) AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
  493.  
  494.    /* move & wrap */
  495.    switch(cmd) {
  496.       case APF:
  497.          if(++t.cursorx > 40)
  498.             if(t.wrap) { t.cursorx-=40; down=1; }
  499.             else         t.cursorx=40;
  500.          break;
  501.  
  502.       case APB:
  503.          if(--t.cursorx < 1)
  504.             if(t.wrap) { t.cursorx+=40; up=1; }
  505.             else         t.cursorx=1;
  506.          break;
  507.  
  508.       case APU:  up=1;           break;
  509.       case APD:  down=1;       break;
  510.       case APR:  t.cursorx=1;  break;
  511.  
  512.       case APA:
  513.          t.hold_mosaic = 0;
  514.          if(t.wrap) {    /* wrap !! (SKY-NET *200070000000004a#) */
  515.             if(x <    1)    { x += 40;    y--; }
  516.             if(x > 40)    { x -= 40;    y++; }
  517.             if(y <    1)      y += rows;
  518.             if(y > rows)  y -= rows;
  519.          }
  520.          else {
  521.             if(x <    1)    x =  1;
  522.             if(x > 40)    x = 40;
  523.             if(y <    1)    y =  1;
  524.             if(y > rows)  y = rows;
  525.          }
  526.  
  527.          t.cursorx=x;
  528.          t.cursory=y;
  529.          break;
  530.    }
  531.  
  532.    if(up) {
  533.       t.hold_mosaic = 0;
  534.       if(t.scroll_area && t.scroll_impl &&
  535.          t.cursory == t.scroll_upper)  scroll(0);
  536.       else
  537.          if(--t.cursory < 1)
  538.             if(t.wrap)    t.cursory += rows;
  539.             else        t.cursory  = 1;
  540.    }
  541.  
  542.    if(down) {
  543.       t.hold_mosaic = 0;
  544.       if(t.scroll_area && t.scroll_impl &&
  545.          t.cursory == t.scroll_lower)  scroll(1);
  546.       else
  547.          if(++t.cursory > rows)
  548.             if(t.wrap)    t.cursory -= rows;
  549.             else        t.cursory  = rows;
  550.    }
  551.  
  552.    /* draw new cursor */
  553.    if(t.cursor_on) AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
  554. }
  555.  
  556.  
  557. /*
  558.  * process a code from the primary control set C0 (0x00 - 0x1f).
  559.  * Returns 1 when DCT is received, else 0.
  560.  */
  561.  
  562. int BTXService::primary_control_C0(int c1)    /* page 118, annex 6 */
  563. {
  564.    int c2, x, y;
  565.  
  566.    switch(c1) {
  567.  
  568.       case APB:
  569.          D(printf("APB active position back\n"));
  570.          move_cursor(APB);
  571.          break;
  572.  
  573.       case APF:
  574.          D(printf("APF active position forward\n"));
  575.          move_cursor(APF);
  576.          break;
  577.  
  578.       case APD:
  579.          D(printf("APD active position down\n"));
  580.          move_cursor(APD);
  581.          break;
  582.  
  583.       case APU:
  584.          D(printf("APU active position up\n"));
  585.          move_cursor(APU);
  586.          break;
  587.  
  588.       case CS:
  589.          D(printf("CS  clear screen\n"));
  590.          t.leftright[0] = t.save_left;
  591.          clearscreen();
  592.          break;
  593.  
  594.       case APR:
  595.          D(printf("APR active position return\n"));
  596.          move_cursor(APR);
  597.          break;
  598.  
  599.       case LS1:
  600.       case LS0:
  601.          c2 = (c1==LS1) ? 1 : 0;
  602.          D(printf("LS%d locking shift G%d left\n", c2, c2));
  603.          t.leftright[0] = c2;  /* G0 or G1 !! */
  604.          t.save_left = c2;
  605.          break;
  606.  
  607.       case CON:
  608.          D(printf("CON cursor on\n"));
  609.          if(!t.cursor_on) {
  610.             t.cursor_on = 1;
  611.             AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
  612.          }
  613.          break;
  614.  
  615.       case RPT:
  616.          D(printf("RPT repeat last char\n"));
  617.          c2 = layer2getc() & 0x3f;
  618.  
  619.          if(reachedEOF)
  620.              break;
  621.  
  622.          D(printf("    %d times\n", c2));
  623.          while(c2--)  output(t.lastchar);
  624.          break;
  625.  
  626.       case COF:
  627.          D(printf("COF cursor off\n"));
  628.          if(t.cursor_on) {
  629.             t.cursor_on = 0;
  630.             AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
  631.          }
  632.          break;
  633.  
  634.       case CAN:
  635.          D(printf("CAN cancel\n"));
  636.          y = t.cursory-1;
  637.          screen[y][t.cursorx-1].chr = ' ';
  638.          screen[y][t.cursorx-1].set = PRIM;
  639.          for(x=t.cursorx; x<40; x++) {    /* clear to the right */
  640.             screen[y][x].chr    = ' ';
  641.             screen[y][x].set    = PRIM;
  642.             screen[y][x].mark    = 0;
  643.             screen[y][x].attr    = screen[y][t.cursorx-1].attr;
  644.             screen[y][x].fg     = screen[y][t.cursorx-1].fg;
  645.             screen[y][x].bg     = screen[y][t.cursorx-1].bg;
  646.          }
  647.          for(x=t.cursorx-1; x<40; x++)    redrawc(x+1, y+1);
  648.          break;
  649.  
  650.       case SS2:
  651.          D(printf("SS2 single shift G2 left\n"));
  652.          t.sshift = G2;
  653.          break;
  654.  
  655.       case ESC:
  656.          D(printf("ESC escape sequence\n"));
  657.          do_ESC();
  658.          break;
  659.  
  660.       case SS3:
  661.          D(printf("SS3 single shift G3 left\n"));
  662.          t.sshift = G3;
  663.          break;
  664.  
  665.       case APH:
  666.          D(printf("APH active position home\n"));
  667.          move_cursor(APA, 1, 1);
  668.          t.par_attr = 0;
  669.          t.par_fg = WHITE;
  670.          t.par_bg = TRANSPARENT;
  671.          break;
  672.  
  673.       case US:
  674.          D(printf("US  unit separator (or APA)\n"));
  675.          do_US();
  676.          break;
  677.  
  678.       default:
  679.          D(printf("??? unprocessed control character 0x%02x - ignored\n", c1));
  680.          if(c1 == DCT)    return 1;
  681.    }
  682.  
  683.    return 0;
  684. }
  685.  
  686.  
  687. /*
  688.  * process a code from the supplementary control set C1 (0x80 - 0x9f).
  689.  * 'fullrow' indicates attribute application to the complete row.
  690.  * Most codes advance active cursor position by one !
  691.  */
  692.  
  693. void BTXService::supplementary_control_C1(int c1, int fullrow)    /* page 121, annex 6 */
  694. {
  695.    int adv, mode = fullrow ? 2 : t.serialmode;
  696.  
  697.    switch(c1) {
  698.                      /* serial     parallel */
  699.       case 0x80:     /*  ABK       BKF      */
  700.       case 0x81:     /*  ANR       RDF      */
  701.       case 0x82:     /*  ANG       GRF      */
  702.       case 0x83:     /*  ANY       YLF      */
  703.       case 0x84:     /*  ANB       BLF      */
  704.       case 0x85:     /*  ANM       MGF      */
  705.       case 0x86:     /*  ANC       CNF      */
  706.       case 0x87:     /*  ANW       WHF      */
  707.          D(printf("set foreground to color #%d %s\n", t.clut*8+c1-0x80,
  708.          (mode==1) ? "(+ unload L set)" : ""));
  709.      set_attr(ATTR_FOREGROUND, 1, t.clut*8+c1-0x80, mode);
  710.      if(mode==1) {
  711.         t.leftright[0] = t.save_left;
  712.      }
  713.          break;
  714.  
  715.       case FSH:
  716.          D(printf("FSH flashing begin\n"));
  717.      /* set_attr(ATTR_FLASH, 1, 0, mode); */
  718.          break;
  719.  
  720.       case STD:
  721.          D(printf("STD flashing steady\n"));
  722.      /* set_attr(ATTR_FLASH, 0, 0, mode); */
  723.          break;
  724.  
  725.       case EBX:
  726.          D(printf("EBX end of window\n"));
  727.      /* set_attr(ATTR_WINDOW, 0, 0, mode); */
  728.          break;
  729.  
  730.       case SBX:
  731.          D(printf("SBX start of window\n"));
  732.      /* set_attr(ATTR_WINDOW, 1, 0, mode); */
  733.          break;
  734.  
  735.       case NSZ:
  736.          D(printf("NSZ normal size\n"));
  737.      set_attr(ATTR_NODOUBLE, 1, 0, mode);
  738.          break;
  739.  
  740.       case DBH:
  741.          D(printf("DBH double height\n"));
  742.      set_attr(ATTR_YDOUBLE, 1, 0, mode);
  743.          break;
  744.  
  745.       case DBW:
  746.          D(printf("DBW double width\n"));
  747.      set_attr(ATTR_XDOUBLE, 1, 0, mode);
  748.          break;
  749.  
  750.       case DBS:
  751.          D(printf("DBS double size\n"));
  752.      set_attr(ATTR_XYDOUBLE, 1, 0, mode);
  753.          break;
  754.  
  755.                      /* serial     parallel */
  756.       case 0x90:     /*  MBK       BKB      */
  757.       case 0x91:     /*  MSR       RDB      */
  758.       case 0x92:     /*  MSG       GRB      */
  759.       case 0x93:     /*  MSY       YLB      */
  760.       case 0x94:     /*  MSB       BLB      */
  761.       case 0x95:     /*  MSM       MGB      */
  762.       case 0x96:     /*  MSC       CNB      */
  763.       case 0x97:     /*  MSW       WHB      */
  764.      /* at fullrow control the parallel set is used ! */
  765.          D(printf("set %s to color #%d\n", (mode==1) ?
  766.          "mosaic foreground (+ invoke L set)" : "background",
  767.          t.clut*8+c1-0x90));
  768.      if(mode==1) {
  769.         set_attr(ATTR_FOREGROUND, 1, t.clut*8+c1-0x90, 1);
  770.         t.save_left = t.leftright[0];
  771.         t.leftright[0] = L;
  772.      }
  773.      else set_attr(ATTR_BACKGROUND, 1, t.clut*8+c1-0x90, mode);
  774.          break;
  775.  
  776.       case CDY:
  777.          D(printf("CDY conceal display\n"));
  778.      set_attr(ATTR_CONCEALED, 1, 0, mode);
  779.          break;
  780.  
  781.       case SPL:
  782.          D(printf("SPL stop lining\n"));
  783.      set_attr(ATTR_UNDERLINE, 0, 0, mode);
  784.          break;
  785.  
  786.       case STL:
  787.          D(printf("STL start lining\n"));
  788.      set_attr(ATTR_UNDERLINE, 1, 0, mode);
  789.          break;
  790.  
  791.       case CSI:
  792.          D(printf("CSI control sequence introducer\n"));
  793.          adv = do_CSI();
  794.          break;
  795.  
  796.       case 0x9c:
  797.          if(mode==1) {
  798.             D(printf("BBD black background\n"));
  799.         set_attr(ATTR_BACKGROUND, 1, t.clut*8+BLACK, 1);
  800.          } else {
  801.             D(printf("NPO normal polarity\n"));
  802.         set_attr(ATTR_INVERTED, 0, 0, mode);
  803.          }
  804.          break;
  805.  
  806.       case 0x9d:
  807.          if(mode==1) {
  808.             D(printf("NBD new background\n"));
  809.         set_attr(ATTR_BACKGROUND, 1,
  810.              screen[t.cursory-1][t.cursorx-1].fg, 1);
  811.          } else {
  812.             D(printf("IPO inverted polarity\n"));
  813.         set_attr(ATTR_INVERTED, 1, 0, mode);
  814.          }
  815.          break;
  816.  
  817.       case 0x9e:
  818.          if(mode==1) {
  819.             D(printf("HMS hold mosaic\n"));
  820.         t.hold_mosaic = 1;
  821.          } else {
  822.             D(printf("TRB transparent background\n"));
  823.         set_attr(ATTR_BACKGROUND, 1, TRANSPARENT, mode);
  824.          }
  825.          break;
  826.  
  827.       case 0x9f:
  828.          if(mode==1) {
  829.             D(printf("RMS release mosaic\n"));
  830.         t.hold_mosaic = 0;
  831.          } else {
  832.             D(printf("STC stop conceal\n"));
  833.         set_attr(ATTR_CONCEALED, 0, 0, mode);
  834.          }
  835.          break;
  836.    }
  837.  
  838.    if(reachedEOF)
  839.        return;
  840.  
  841.    /* serial attribute controls advance cursor 1 char forwards !  (page 90) */
  842.    if(mode==1 && (c1!=CSI || adv) )
  843.       if(t.hold_mosaic)  output(t.lastchar);  /* HMS/RMS (page 96) */
  844.       else                 move_cursor(APF);
  845. }
  846.  
  847. void BTXService::write(const STRPTR what,int len)
  848. {
  849.     App->AppChannel->PutStringDirect(what,len);
  850. }
  851.  
  852. void BTXService::do_US()  /* page 85/86 */
  853. {
  854.     static UBYTE TFI_string[] = { SOH, US, 0x20, 0x7f, 0x4c, ETB };    // 0x4c = supports telesoftware and transparent mode
  855.     int c2, c3, alphamosaic = 0;
  856.  
  857.     /* implicite return from service break !!! (any US sequence !?!) */
  858.     if(t.service_break) {
  859.         t = backup;
  860.         move_cursor(APA, t.cursory, t.cursorx);
  861.     }
  862.  
  863.     for(;;)
  864.     {
  865.         c2 = layer2getc();
  866.  
  867.         if(reachedEOF)
  868.             return;
  869.  
  870.         if(c2 != 0x1f)
  871.             break;
  872.     }
  873.  
  874.     switch(c2) {
  875.         case 0x20:  /* annex 7.3 */
  876.             D(printf("    TFI Terminal Facility Identifier\n"));
  877.             c3 = layer2getc();
  878.  
  879.             if(reachedEOF)
  880.                 return;
  881.  
  882.             if(c3==0x40) {
  883.                 D(printf("       TFI request\n"));
  884.                 write((STRPTR)&TFI_string[0], sizeof(TFI_string));
  885.             }
  886.             else {
  887.                 D(printf("       TFI echo 0x%02x\n", c3));
  888.                 do {
  889.                     c3 = layer2getc();
  890.  
  891.                     if(reachedEOF)
  892.                         return;
  893.  
  894.                     D(printf("       TFI echo 0x%02x\n", c3));
  895.                 }
  896.                 while(c3 & 0x20);  /* extension bit */
  897.             }
  898.             break;
  899.  
  900.         case 0x23:
  901.             D(printf("    define DRCS\n"));
  902.             do_DRCS();
  903.             break;
  904.  
  905.         case 0x26:
  906.             D(printf("    define color\n"));
  907.             do_DEFCOLOR();
  908.             break;
  909.  
  910.         case 0x29:
  911.             D(printf("    FIF\n"));
  912.             do_FIF();
  913.             break;
  914.  
  915.         case 0x2d:  /* page 155 */
  916.             D(printf("    define Format\n"));
  917.             do_DEFFORMAT();
  918.             break;
  919.  
  920.         case 0x2f:  /* page 157 */
  921.             D(printf("    Reset sequence\n"));
  922.             do_RESET();
  923.             alphamosaic = 1;
  924.             break;
  925.  
  926.         case 0x3e:  /* annex 7.4 */
  927.             D(printf("    telesoftware\n"));
  928.             do_Telesoftware();
  929.             break;
  930.  
  931.         case 0x3f:    /* annex 7.2 */
  932.             D(printf("    transparent data\n"));
  933.  
  934.                 // How many bytes of transparent data are to follow?
  935.  
  936.             c3 = layer2getc();
  937.  
  938.             if(reachedEOF)
  939.                 return;
  940.  
  941.                 // Should be 254 bytes maximum
  942.  
  943.             transparent_max = c3;
  944.             transparent_collected = 0;
  945.  
  946.             do_TransparentData();
  947.             break;
  948.  
  949.         default:      /* APA active position addressing */
  950.             if(c2<0x40)  D(printf("    unknown US sequence\n"));
  951.             else {
  952.                 alphamosaic = 1;
  953.                 D(printf("    new row    %2d\n", c2 & 0x3f));
  954.                 c3 = layer2getc();
  955.  
  956.                 if(reachedEOF)
  957.                     return;
  958.  
  959.                 D(printf("    new column %2d\n", c3 & 0x3f));
  960.                 move_cursor(APA, c2 & 0x3f, c3 & 0x3f);
  961.                 t.par_attr = 0;
  962.                 t.par_fg = WHITE;
  963.                 t.par_bg = TRANSPARENT;
  964.             }
  965.             break;
  966.     }
  967.  
  968.     if(reachedEOF)
  969.         return;
  970.  
  971.         // Check if we are in a nested VPDE, within a transparent
  972.         // data transmission
  973.  
  974.     if(transparent_max > 0)
  975.     {
  976.         D(printf("    continue transparent data\n"));
  977.         do_TransparentData();
  978.     }
  979.  
  980.     /* VPDE = US x data. Each VPDE has to be followed by the next VPDE
  981.      * immediately (page 85). The alphamosaic VPDE is introduced by APA or
  982.      * by one of the reset functions ! Any remaining data (errors) after all
  983.      * other VPDE's has to be skipped (*17420101711a#).
  984.      */
  985.     if(!alphamosaic) {
  986.         while( (c2 = layer2getc()) != US )
  987.         {
  988.             if(reachedEOF)
  989.                 return;
  990.  
  991.             D(printf("skipping to next US\n"));
  992.         }
  993.  
  994.         if(reachedEOF)
  995.             return;
  996.  
  997.         D(printf("\n"));
  998.         layer2ungetc(US);
  999.     }
  1000. }
  1001.  
  1002. void BTXService::do_ESC()
  1003. {
  1004.    int y, c2, c3, c4;
  1005.  
  1006.    c2 = layer2getc();
  1007.  
  1008.    if(reachedEOF)
  1009.       return;
  1010.  
  1011.    switch(c2) {
  1012.  
  1013.       case 0x22:
  1014.          D(printf("    invoke C1\n"));
  1015.          c3 = layer2getc();
  1016.  
  1017.          if(reachedEOF)
  1018.             return;
  1019.  
  1020.          D(printf("       (%s)\n", c3==0x40 ? "serial" : "parallel"));
  1021.      if(c3==0x40)  t.serialmode = 1;
  1022.      else {
  1023.         t.serialmode = 0;
  1024.         t.leftright[0] = t.save_left;
  1025.      }
  1026.          break;
  1027.  
  1028.       case 0x23:
  1029.          D(printf("    set attributes\n"));
  1030.          c3 = layer2getc();
  1031.  
  1032.          if(reachedEOF)
  1033.             return;
  1034.  
  1035.          switch(c3) {
  1036.             case 0x20:
  1037.                D(printf("       full screen background\n"));
  1038.                c4 = layer2getc();
  1039.  
  1040.                if(reachedEOF)
  1041.                   return;
  1042.  
  1043.                D(printf("          color = %d\n",
  1044.            c4==0x5e ? TRANSPARENT : t.clut*8+c4-0x50));
  1045.            for(y=0; y<24; y++)
  1046.               AppDisplay->define_fullrow_bg(y, c4==0x5e ?
  1047.                     TRANSPARENT : t.clut*8+c4-0x50);
  1048.                break;
  1049.             case 0x21:
  1050.                D(printf("       full row\n"));
  1051.                c4 = layer2getc();
  1052.  
  1053.                if(reachedEOF)
  1054.                   return;
  1055.  
  1056.            D(printf("          "));
  1057.            supplementary_control_C1(c4+0x40, 1);
  1058.                break;
  1059.          }
  1060.          break;
  1061.  
  1062.       case 0x28:
  1063.  
  1064.       case 0x29:
  1065.       case 0x2a:
  1066.       case 0x2b:
  1067.          D(printf("    load G%d with\n", c2 - 0x28));
  1068.          c3 = layer2getc();
  1069.  
  1070.          if(reachedEOF)
  1071.             return;
  1072.  
  1073.          switch(c3) {
  1074.             case 0x40:
  1075.                D(printf("       'primary graphic'\n"));
  1076.                t.G0123L[c2 - 0x28] = PRIM;
  1077.                t.prim = c2 - 0x28;
  1078.                break;
  1079.             case 0x62:
  1080.                D(printf("       'supplementary graphic'\n"));
  1081.                t.G0123L[c2 - 0x28] = SUPP;
  1082.                t.supp = c2 - 0x28;
  1083.                break;
  1084.             case 0x63:
  1085.                D(printf("       '2nd supplementary mosaic'\n"));
  1086.                t.G0123L[c2 - 0x28] = SUP2;
  1087.                break;
  1088.             case 0x64:
  1089.                D(printf("       '3rd supplementary mosaic'\n"));
  1090.                t.G0123L[c2 - 0x28] = SUP3;
  1091.                break;
  1092.             case 0x20:
  1093.            D(printf("       DRCS\n"));
  1094.                c4 = layer2getc();
  1095.  
  1096.                if(reachedEOF)
  1097.                   return;
  1098.  
  1099.                if(c4 != 0x40)  D(printf("HAEH  (ESC 0x%02x 0x20 0x%02x)\n", c2, c4));
  1100.            else            D(printf("\n"));
  1101.                t.G0123L[c2 - 0x28] = DRCS;
  1102.                break;
  1103.          }
  1104.          break;
  1105.  
  1106.  
  1107.       case 0x6e:
  1108.          D(printf("    LS2 locking shift G2 left\n"));
  1109.          t.leftright[0] = G2;
  1110.      t.save_left = G2;
  1111.          break;
  1112.  
  1113.       case 0x6f:
  1114.          D(printf("    LS3 locking shift G3 left\n"));
  1115.          t.leftright[0] = G3;
  1116.      t.save_left = G3;
  1117.          break;
  1118.  
  1119.       case 0x7c:
  1120.          D(printf("    LS3R locking shift G3 right\n"));
  1121.          t.leftright[1] = G3;
  1122.          break;
  1123.  
  1124.       case 0x7d:
  1125.          D(printf("    LS2R locking shift G2 right\n"));
  1126.          t.leftright[1] = G2;
  1127.          break;
  1128.  
  1129.       case 0x7e:
  1130.          D(printf("    LS1R locking shift G1 right\n"));
  1131.          t.leftright[1] = G1;
  1132.          break;
  1133.    }
  1134. }
  1135.  
  1136.  
  1137. /*
  1138.  * Process one control sequence. Return whether or not the cursor position
  1139.  * has to be advanced by one char (in case of serialmode).
  1140.  *
  1141.  * Anscheinend sollen nur die FLASH-controls den Cursor eins weiterstellen -
  1142.  * steht zwar nirgends, sieht aber am besten aus !!!
  1143.  */
  1144.  
  1145. int BTXService::do_CSI()
  1146. {
  1147.    int c2, c3, upper, lower;
  1148.  
  1149.    c2 = layer2getc();
  1150.  
  1151.    if(reachedEOF)
  1152.       return(0);
  1153.  
  1154.    if(c2 == 0x42) {
  1155.       D(printf("    STC stop conceal\n"));
  1156.       set_attr(ATTR_CONCEALED, 0, 0, t.serialmode);
  1157.       return 0;
  1158.    }
  1159.  
  1160.    D(printf("\n"));
  1161.    c3 = layer2getc();
  1162.  
  1163.    if(reachedEOF)
  1164.       return(0);
  1165.  
  1166.    /* protection only available as fullrow controls ?? (page 135) */
  1167.    if(c2 == 0x31 && c3 == 0x50) {
  1168.       D(printf("       PMS protected mode start\n"));
  1169.       set_attr(ATTR_PROTECTED, 1, 0, 2);
  1170.       return 0;
  1171.    }
  1172.    if(c2 == 0x31 && c3 == 0x51) {
  1173.       D(printf("       PMC protected mode cancel\n"));
  1174.       set_attr(ATTR_PROTECTED, 0, 0, 2);
  1175.       return 0;
  1176.    }
  1177.    if(c2 == 0x32 && c3 == 0x53) {
  1178.       D(printf("       MMS marked mode start\n"));
  1179.       /* set_attr(ATTR_MARKED, 1, 0, t.serialmode); */
  1180.       return 0;
  1181.    }
  1182.    if(c2 == 0x32 && c3 == 0x54) {
  1183.       D(printf("       MMT marked mode stop\n"));
  1184.       /* set_attr(ATTR_MARKED, 0, 0, t.serialmode); */
  1185.       return 0;
  1186.    }
  1187.  
  1188.    switch(c3) {
  1189.  
  1190.       case 0x40:
  1191.          D(printf("       invoke CLUT%d\n", c2 - 0x2f));
  1192.  
  1193.  
  1194.      t.clut = c2 - 0x30;
  1195.          return 0;
  1196.  
  1197.       case 0x41:
  1198.          switch(c2) {
  1199.             case 0x30:
  1200.                D(printf("       IVF inverted flash\n"));
  1201.                return 1;
  1202.             case 0x31:
  1203.                D(printf("       RIF reduced intesity flash\n"));
  1204.                return 1;
  1205.             case 0x32:
  1206.             case 0x33:
  1207.             case 0x34:
  1208.                D(printf("       FF%c fast flash %c\n", c2-1, c2-1));
  1209.                return 1;
  1210.             case 0x35:
  1211.                D(printf("       ICF increment flash\n"));
  1212.                return 1;
  1213.             case 0x36:
  1214.                D(printf("       DCF decrement flash\n"));
  1215.                return 1;
  1216.          }
  1217.          break;
  1218.  
  1219.       case 0x60:
  1220.          switch(c2) {
  1221.             case 0x30:
  1222.                D(printf("       SCU explicit scroll up\n"));
  1223.            if(t.scroll_area) scroll(1);
  1224.                return 0;
  1225.             case 0x31:
  1226.                D(printf("       SCD explicit scroll down\n"));
  1227.            if(t.scroll_area) scroll(0);
  1228.  
  1229.                return 0;
  1230.             case 0x32:
  1231.                D(printf("       AIS activate implicite scrolling\n"));
  1232.            t.scroll_impl = 1;
  1233.                return 0;
  1234.             case 0x33:
  1235.                D(printf("       DIS deactivate implicite scrolling\n"));
  1236.            t.scroll_impl = 0;
  1237.                return 0;
  1238.          }
  1239.          break;
  1240.  
  1241.       default:    /* definition of scrolling area (page 137) */
  1242.      upper = c2 & 0x0f;
  1243.      if(c3>=0x30 && c3<=0x39)  upper = upper*10 + (c3&0x0f);
  1244.      D(printf("       upper row: %2d\n", upper));
  1245.      if(c3>=0x30 && c3<=0x39)
  1246.      {
  1247.         c3 = layer2getc();
  1248.  
  1249.         if(reachedEOF)
  1250.            return(0);
  1251.  
  1252.         D(printf("\n"));
  1253.      }
  1254.  
  1255.      if(c3!=0x3b)  D(fprintf(stderr,"XBTX: scrolling area - protocol !\n"));
  1256.  
  1257.      lower = layer2getc() & 0x0f;
  1258.  
  1259.      if(reachedEOF)
  1260.         return(0);
  1261.  
  1262.      D(printf("\n"));
  1263.      c3 = layer2getc();
  1264.  
  1265.      if(reachedEOF)
  1266.         return(0);
  1267.  
  1268.      if(c3>=0x30 && c3<=0x39)  lower = lower*10 + (c3&0x0f);
  1269.      D(printf("       lower row: %2d", lower));
  1270.      if(c3>=0x30 && c3<=0x39)
  1271.      {
  1272.         D(printf("\n"));
  1273.         c3=layer2getc();
  1274.  
  1275.         if(reachedEOF)
  1276.            return(0);
  1277.  
  1278.         D(printf("    "));
  1279.      }
  1280.  
  1281.      if(c3==0x55) {
  1282.         D(printf("   CSA create scrolling area\n"));
  1283.         if(upper>=2 && lower<rows && lower>=upper) {
  1284.            t.scroll_upper = upper;
  1285.            t.scroll_lower = lower;
  1286.            t.scroll_area = 1;
  1287.         }
  1288.      }
  1289.      if(c3==0x56) {
  1290.         D(printf("   CSD delete scrolling area\n"));
  1291.         t.scroll_area = 0;
  1292.      }
  1293.          return 0;
  1294.    }
  1295.    return 0;
  1296. }
  1297.  
  1298.  
  1299. void BTXService::do_DRCS()     /* (page 139ff) */
  1300. {
  1301.    int c3, c4, c5, c6, c7, c8;
  1302.  
  1303.    c3 = layer2getc();
  1304.  
  1305.    if(reachedEOF)
  1306.       return;
  1307.  
  1308.    if(c3 == 0x20) {
  1309.       D(printf("       DRCS header unit\n"));
  1310.       c4 = layer2getc();
  1311.  
  1312.       if(reachedEOF)
  1313.          return;
  1314.  
  1315.       if(c4==0x20 || c4==0x28) {
  1316.      D(printf("          %s existing DRCS\n", (c4==0x20) ? "keep" : "delete"));
  1317.  
  1318.      if(c4==0x28)  AppDisplay->free_DRCS();
  1319.      c5 = layer2getc();
  1320.  
  1321.      if(reachedEOF)
  1322.         return;
  1323.  
  1324.       } else c5 = c4;
  1325.       if(c5 == 0x20) {
  1326.      D(printf("\n"));
  1327.      c6 = layer2getc();
  1328.  
  1329.      if(reachedEOF)
  1330.         return;
  1331.  
  1332.       } else c6 = c5;
  1333.       if(c6 == 0x40) {
  1334.      D(printf("\n"));
  1335.      c7 = layer2getc();
  1336.  
  1337.      if(reachedEOF)
  1338.         return;
  1339.  
  1340.       } else c7 = c6;
  1341.  
  1342.       switch(c7 & 0xf) {
  1343.          case 6:
  1344.         D(printf("          12x12 pixel\n"));
  1345.         t.drcs_w = 12;
  1346.         t.drcs_h = 12;
  1347.         break;
  1348.      case 7:
  1349.         D(printf("          12x10 pixel\n"));
  1350.         t.drcs_w = 12;
  1351.         t.drcs_h = 10;
  1352.         break;
  1353.      case 10:
  1354.         D(printf("          6x12 pixel\n"));
  1355.         t.drcs_w = 6;
  1356.         t.drcs_h = 12;
  1357.         break;
  1358.      case 11:
  1359.         D(printf("          6x10 pixel\n"));
  1360.         t.drcs_w = 6;
  1361.         t.drcs_h = 10;
  1362.         break;
  1363.      case 12:
  1364.         D(printf("          6x5 pixel\n"));
  1365.         t.drcs_w = 6;
  1366.         t.drcs_h = 5;
  1367.         break;
  1368.      case 15:
  1369.         D(printf("          6x6 pixel\n"));
  1370.         t.drcs_w = 6;
  1371.         t.drcs_h = 6;
  1372.         break;
  1373.       }
  1374.  
  1375.       c8 = layer2getc();
  1376.  
  1377.       if(reachedEOF)
  1378.          return;
  1379.  
  1380.       D(printf("          %d bit/pixel\n", c8 & 0xf));
  1381.       t.drcs_bits = c8 & 0xf;
  1382.       t.drcs_step = (t.drcs_h>=10 && t.drcs_w*t.drcs_bits==24)    ?  2 : 1;
  1383.    }
  1384.    else {
  1385.       D(printf("       DRCS pattern transfer unit (char: 0x%02x)\n", c3));
  1386.       do_DRCS_data(c3);
  1387.    }
  1388. }
  1389.  
  1390.  
  1391. /*
  1392.  * load and define dynamic characters, first character is 'c'.
  1393.  * more than one bitplane of a character may be loaded simultaneously !
  1394.  */
  1395.  
  1396. void BTXService::do_DRCS_data(int c)
  1397. {
  1398.    int c4, i, n, planes=0, planemask=0, byte=0;
  1399.    int maxbytes, start = c;
  1400.  
  1401.    maxbytes = 2*t.drcs_h;
  1402.    if(t.drcs_h<10)    maxbytes *= 2;
  1403.  
  1404.    memset(data,0,sizeof(data));
  1405.  
  1406.    do {
  1407.       c4 = layer2getc();
  1408.  
  1409.       if(reachedEOF)
  1410.          return;
  1411.  
  1412.       switch(c4) {
  1413.          case 0x20:  /* S-bytes */
  1414.          case 0x2f:
  1415.         D(printf("          fill rest of char with %d\n", c4 & 1));
  1416.         for(; byte<maxbytes; byte++)
  1417.            for(n=0; n<4; n++)
  1418.               if(planemask & (1<<n)) data[n][byte] = (UBYTE)((c4==0x20) ? 0 : 0xff);
  1419.         break;
  1420.      case 0x21:
  1421.      case 0x22:
  1422.      case 0x23:
  1423.      case 0x24:
  1424.      case 0x25:
  1425.      case 0x26:
  1426.      case 0x27:
  1427.      case 0x28:
  1428.      case 0x29:
  1429.      case 0x2a:
  1430.         D(printf("          repeat last row %d times\n", c4 & 0xf));
  1431.         if(byte&1) byte++;     /* pad to full row (assume 0) */
  1432.             for(i=0; i<(c4 & 0xf); i++) {
  1433.            for(n=0; n<4; n++)
  1434.               if(planemask & (1<<n)) {
  1435.              data[n][byte]     = (UBYTE)(byte ? data[n][byte-2] : 0);
  1436.              data[n][byte+1] = (UBYTE)(byte ? data[n][byte-2+1] : 0);
  1437.              if(t.drcs_h<10) {
  1438.             data[n][byte+2] = (UBYTE)(byte ? data[n][byte-2] : 0);
  1439.             data[n][byte+3] = (UBYTE)(byte ? data[n][byte-2+1] : 0);
  1440.              }
  1441.           }
  1442.            byte += 2;
  1443.            if(t.drcs_h<10)    byte += 2;
  1444.         }
  1445.             break;
  1446.      case 0x2c:
  1447.      case 0x2d:
  1448.         D(printf("          full row %d\n", c4 & 1));
  1449.         if(byte&1) byte++;     /* pad to full row (assume 0) */
  1450.             for(n=0; n<4; n++)
  1451.            if(planemask & (1<<n)) {
  1452.           data[n][byte]   = (UBYTE)((c4==0x2c) ? 0 : 0xff);
  1453.           data[n][byte+1] = (UBYTE)((c4==0x2c) ? 0 : 0xff);
  1454.           if(t.drcs_h<10) {
  1455.              data[n][byte+2] = (UBYTE)((c4==0x2c) ? 0 : 0xff);
  1456.              data[n][byte+3] = (UBYTE)((c4==0x2c) ? 0 : 0xff);
  1457.           }
  1458.            }
  1459.             byte += 2;
  1460.         if(t.drcs_h<10)  byte += 2;
  1461.             break;
  1462.      case 0x2e:
  1463.         D(printf("          fill rest of char with last row\n"));
  1464.         if(byte&1) byte++;     /* pad to full row (assume 0) */
  1465.             while(byte<maxbytes) {
  1466.            for(n=0; n<4; n++)
  1467.               if(planemask & (1<<n)) {
  1468.              data[n][byte]     = data[n][byte-2];
  1469.              data[n][byte+1] = data[n][byte-2+1];
  1470.           }
  1471.            byte += 2;
  1472.         }
  1473.             break;
  1474.  
  1475.          case 0x30:  /* B-bytes */
  1476.          case 0x31:
  1477.          case 0x32:
  1478.          case 0x33:
  1479.         if(byte) {
  1480.            D(printf("          new plane ahead - filling up\n"));
  1481.            byte = maxbytes;   /* pad to full plane */
  1482.            layer2ungetc(c4);
  1483.         }
  1484.         else {
  1485.            D(printf("          start of pattern block (plane %d)\n", c4 & 0xf));
  1486.            for(i=0; i<2*FONT_HEIGHT; i++)  data[c4 & 0xf][i] = 0;
  1487.            planemask |= 1 << (c4 & 0xf);
  1488.         }
  1489.         break;
  1490.  
  1491.      default:
  1492.             if(c4<0x20 || c4>0x7f) {
  1493.            D(printf("          end of pattern data\n"));
  1494.            layer2ungetc(c4);
  1495.            if(byte)  byte = maxbytes;
  1496.         }
  1497.  
  1498.  
  1499.         else {     /* D-bytes */
  1500.            D(printf("          pattern data\n"));
  1501.            if(t.drcs_w==6) {   /* low res */
  1502.           for(n=0; n<4; n++)
  1503.              if(planemask & (1<<n))  {
  1504.             data[n][byte] =
  1505.                  (UBYTE)(((c4&32)?0x30:0) | ((c4&16)?0x0c:0) | ((c4&8)?0x03:0));
  1506.             data[n][byte+1] =
  1507.                  (UBYTE)(((c4&4)?0x30:0) | ((c4&2)?0x0c:0) | ((c4&1)?0x03:0));
  1508.              }
  1509.           byte += 2;
  1510.            }
  1511.            else {
  1512.           for(n=0; n<4; n++)
  1513.              if(planemask & (1<<n))  data[n][byte] = (UBYTE)(c4 & 0x3f);
  1514.           byte++;
  1515.            }
  1516.  
  1517.            if(!(byte&1) && t.drcs_h<10) {  /* duplicate row ? */
  1518.           for(n=0; n<4; n++)
  1519.                  if(planemask & (1<<n)) {
  1520.             data[n][byte]    = data[n][byte-2];
  1521.             data[n][byte+1] = data[n][byte-2+1];
  1522.              }
  1523.           byte += 2;
  1524.            }
  1525.         }
  1526.         break;
  1527.  
  1528.       } /* switch */
  1529.  
  1530.       if(byte == maxbytes) {  /* plane is complete */
  1531.      for(n=0; n<4; n++)  if(planemask & (1<<n))  planes++;
  1532.      planemask = 0;
  1533.      byte = 0;
  1534.      if(planes == t.drcs_bits) {  /* DRC is complete */
  1535.         D(log_DRC(c, t.drcs_bits));
  1536.         AppDisplay->define_raw_DRC(c, &data[0][0], t.drcs_bits);
  1537.         planes = 0;
  1538.         c += t.drcs_step;
  1539.      }
  1540.       }
  1541.  
  1542.  
  1543.    } while(c4>=0x20 && c4<=0x7f);
  1544.  
  1545.    update_DRCS_display(start, c, t.drcs_step);
  1546. }
  1547.  
  1548. #if 0 D(+1)
  1549. /*
  1550.  * pretty print the received character to the LOG file
  1551.  */
  1552. void BTXService::log_DRC(int c, int bits)
  1553. {
  1554.    int n, i, j, k;
  1555.  
  1556.    printf("\n                      DRC # 0x%2x\n", c);
  1557.    for(n=0; n<bits; n++) {
  1558.       printf("                      (plane %d)\n", n);
  1559.       printf("                      --------------------------\n");
  1560.       for(j=0; j<fontheight; j++) {
  1561.      printf("                      |");
  1562.      for(k=0; k<2; k++)
  1563.         for(i=5; i>=0; i--)
  1564.            if(data[n][j*2+k] & (1<<i)) printf("* ");
  1565.            else                        printf("  ");
  1566.      printf("|\n");
  1567.       }
  1568.       printf("                      --------------------------\n\n");
  1569.    }
  1570. }
  1571. #endif
  1572.  
  1573. /*
  1574.  * load and define dynamic colors.
  1575.  */
  1576. void BTXService::do_DEFCOLOR()    /* (page 150ff) */
  1577. {
  1578.    int c3, c4, c5, c6, c7, index, r, g, b;
  1579.  
  1580.    c3 = layer2getc();
  1581.  
  1582.    if(reachedEOF)
  1583.       return;
  1584.  
  1585.    switch(c3) {
  1586.  
  1587.  
  1588.       case 0x20:   /*  US 0x26 0x20 <ICT> <SUR> <SCM>  */
  1589.          D(printf("       color header unit\n"));
  1590.          t.col_modmap = 1;      /* by default modify colormap */
  1591.          c4 = layer2getc();
  1592.  
  1593.          if(reachedEOF)
  1594.             return;
  1595.  
  1596.          if((c4 & 0xf0) == 0x20) {
  1597.         if(c4!=0x20 && c4!=0x22) {
  1598.            D(printf("*** <ICT>: bad value !\n"));
  1599.            D(fprintf(stderr,"XBTX: do_DEFCOLOR(): ICT1 = 0x%02x\n", c4));
  1600.         }
  1601.             D(printf("          <ICT>: load %s\n", c4==0x20 ? "colormap" : "DCLUT"));
  1602.         t.col_modmap = (c4==0x20);
  1603.             c5 = layer2getc();
  1604.  
  1605.             if(reachedEOF)
  1606.                return;
  1607.  
  1608.          } else c5 = c4;
  1609.          if((c5 & 0xf0) == 0x20) {
  1610.             D(printf("          <ICT>: (unit %d)\n", c5&0xf));
  1611.         if(c5!=0x20) {
  1612.            D(printf("*** <ICT>: bad value !\n"));
  1613.            D(fprintf(stderr,"XBTX: do_DEFCOLOR(): ICT2 = 0x%02x\n", c5));
  1614.         }
  1615.             c6 = layer2getc();
  1616.  
  1617.             if(reachedEOF)
  1618.                return;
  1619.  
  1620.          } else c6 = c5;
  1621.          if((c6 & 0xf0) == 0x30) {
  1622.             D(printf("          <SUR>: %d bits\n", c6&0xf));
  1623.         if(c6!=0x34 && c6!=0x35) {
  1624.            D(printf("*** <SUR>: bad value !\n"));
  1625.            D(fprintf(stderr,"XBTX: do_DEFCOLOR(): SUR = 0x%02x\n", c6));
  1626.         }
  1627.             c7 = layer2getc();
  1628.  
  1629.             if(reachedEOF)
  1630.                return;
  1631.  
  1632.          } else c7 = c6;
  1633.          if((c7 & 0xf0) == 0x40) {
  1634.             D(printf("          <SCM>: 0x%02x\n", c7));
  1635.         if(c7!=0x40 && c7!=0x41) {
  1636.            D(printf("*** <SCM>: bad value !\n"));
  1637.            D(fprintf(stderr,"XBTX: do_DEFCOLOR(): SCM = 0x%02x\n", c7));
  1638.         }
  1639.          } else {
  1640.             D(printf("          default header\n"));
  1641.             layer2ungetc(c7);
  1642.          }
  1643.          break;
  1644.  
  1645.       case 0x21:
  1646.          D(printf("       color reset unit\n"));
  1647.      AppDisplay->default_colors();
  1648.          break;
  1649.  
  1650.       default:
  1651.          D(printf("       color transfer unit  (1.Stelle: %d)\n", c3&0xf));
  1652.      index = c3&0xf;
  1653.          c4 = layer2getc();
  1654.  
  1655.          if(reachedEOF)
  1656.             return;
  1657.  
  1658.          if((c4 & 0xf0) == 0x30) { /* c3 zehner, c4 einer */
  1659.             D(printf("                            (2.Stelle: %d)\n", c4&0xf));
  1660.         index = (c3&0xf)*10 + (c4&0xf);
  1661.             c5 = layer2getc();
  1662.  
  1663.             if(reachedEOF)
  1664.                return;
  1665.  
  1666.          } else c5 = c4;
  1667.  
  1668.      if(t.col_modmap) {  /* load colormap */
  1669.         while(c5>=0x40 && c5<=0x7f) {
  1670.            D(printf("          color #%2d:  R G B\n", index));
  1671.            c6 = layer2getc();
  1672.  
  1673.            if(reachedEOF)
  1674.               return;
  1675.  
  1676.            r = (c5&0x20)>>2 | (c5&0x04)    | (c6&0x20)>>4 | (c6&0x04)>>2;
  1677.            g = (c5&0x10)>>1 | (c5&0x02)<<1 | (c6&0x10)>>3 | (c6&0x02)>>1;
  1678.            b = (c5&0x08)    | (c5&0x01)<<2 | (c6&0x08)>>2 | (c6&0x01);
  1679.  
  1680.            D(printf("                      %1x %1x %1x\n", r, g, b));
  1681.            if(index>=16 && index<=31)  AppDisplay->define_color(index++, r, g, b);
  1682.            c5 = layer2getc();
  1683.  
  1684.            if(reachedEOF)
  1685.               return;
  1686.  
  1687.         }
  1688.      }
  1689.      else {  /* load DCLUT */
  1690.         while(c5>=0x40 && c5<=0x7f) {
  1691.            D(printf("          DCLUT[%2d] = %2d\n", index, c5&0x1f));
  1692.            if(index>=0 && index<=3)  AppDisplay->define_DCLUT(index++, c5&0x1f);
  1693.            c5 = layer2getc();
  1694.  
  1695.            if(reachedEOF)
  1696.               return;
  1697.  
  1698.         }
  1699.      }
  1700.  
  1701.      D(printf("          end of color data\n"));
  1702.          layer2ungetc(c5);
  1703.          break;
  1704.    }
  1705. }
  1706.  
  1707.  
  1708. void BTXService::do_DEFFORMAT()   /* format designation  (page 155) */
  1709. {
  1710.    int c3, c4;
  1711.  
  1712.    rows = 24;
  1713.    fontheight = 10;
  1714.    t.wrap  = 1;
  1715.  
  1716.    c3 = layer2getc();
  1717.  
  1718.    if(reachedEOF)
  1719.       return;
  1720.  
  1721.    if((c3&0xf0) == 0x40) {
  1722.       switch(c3) {
  1723.          case 0x41:
  1724.             D(printf("       40 columns by 24 rows\n"));
  1725.         break;
  1726.          case 0x42:
  1727.         D(printf("       40 columns by 20 rows\n"));
  1728.         rows = 20;
  1729.         fontheight = 12;
  1730.         break;
  1731.          default:
  1732.         D(printf("       unrecognized format (using default)\n"));
  1733.         break;
  1734.       }
  1735.       c4 = layer2getc();
  1736.  
  1737.       if(reachedEOF)
  1738.          return;
  1739.    }
  1740.    else c4 = c3;
  1741.  
  1742.    if((c4&0xf0) == 0x70) {
  1743.       D(printf("       wraparound %s\n", (c3&1) ? "inactive" : "active"));
  1744.       t.wrap = (c3 == 0x70) ? 1 : 0;
  1745.    }
  1746.    else {
  1747.       D(printf("       default format\n"));
  1748.       layer2ungetc(c4);
  1749.    }
  1750. }
  1751.  
  1752.  
  1753. void BTXService::do_RESET()  /* reset functions  (page 157) */
  1754. {
  1755.    int y, c3, c4;
  1756.  
  1757.    c3 = layer2getc();
  1758.  
  1759.    if(reachedEOF)
  1760.       return;
  1761.  
  1762.    switch(c3) {
  1763.  
  1764.       case 0x40:   /* (page 158) */
  1765.          D(printf("       service break to row\n"));
  1766.          c4 = layer2getc();
  1767.  
  1768.          if(reachedEOF)
  1769.            return;
  1770.  
  1771.          D(printf("          #%d\n", c4 & 0x3f));
  1772.          backup = t;  /* structure copy */
  1773.          t.leftright[0] = t.prim;  /* PFUSCH !!! */
  1774.          t.leftright[1] = t.supp;
  1775.      t.save_left = t.prim;
  1776.          t.wrap = 0;
  1777.      t.cursor_on = 0;
  1778.      move_cursor(APA, c4 & 0x3f, 1);
  1779.          t.serialmode = 1;
  1780.      t.clut = 0;
  1781.      t.service_break = 1;
  1782.          break;
  1783.  
  1784.       case 0x41:
  1785.       case 0x42:
  1786.          D(printf("       defaults (%s C1)\n", c3&1 ? "serial" : "parallel"));
  1787.          default_sets();
  1788.          t.serialmode = c3 & 1;
  1789.          t.wrap = 1;
  1790.      t.cursor_on = 0;
  1791.      rows = 24;
  1792.      fontheight = 10;
  1793.      for(y=0; y<24; y++)  AppDisplay->define_fullrow_bg(y, BLACK);
  1794.          clearscreen();  /* clearscr resets CLUT, par_attr, cursor pos */
  1795.          break;
  1796.  
  1797.       case 0x43:
  1798.       case 0x44:
  1799.          D(printf("       limited defaults (%s C1)\n", c3&1 ? "serial":"parallel"));
  1800.          default_sets();
  1801.          t.serialmode = c3 & 1;
  1802.          break;
  1803.  
  1804.       case 0x4f:
  1805.          D(printf("       reset to previous state\n"));
  1806.          t = backup;
  1807.      move_cursor(APA, t.cursory, t.cursorx);
  1808.          break;
  1809.    }
  1810. }
  1811.  
  1812.  
  1813. /*
  1814.  * set/reset parallel, serial or fullrow attributes (+ set/delete markers)
  1815.  * (mode: 0=parallel, 1=serial, 2=fullrow)
  1816.  *
  1817.  * MARKER:    (page 91 / annex 1, page 29)
  1818.  *
  1819.  *     parallel: (set in output())
  1820.  *        set wherever an attr is changed
  1821.  *        set at attr changes in writing a continuous string
  1822.  *        delete existing markers in overwritten part of "
  1823.  *        delete when printing and attrs do not change
  1824.  *
  1825.  *     serial:   (set here)
  1826.  *        set at this position
  1827.  */
  1828.  
  1829. void BTXService::set_attr(int a, int set, int col, int mode)
  1830. {
  1831.    int x, y = t.cursory-1, refresh, mattr = a;
  1832.  
  1833.    /* set fullrow background */
  1834.    if(mode==2 && a==ATTR_BACKGROUND) {
  1835.       AppDisplay->define_fullrow_bg(y, col);
  1836.       return;
  1837.    }
  1838.  
  1839.    if(a & ATTR_ANYSIZE)  mattr = ATTR_SIZE;
  1840.  
  1841.    /* serial mode controls set a marker */
  1842.    if(mode==1)    screen[y][t.cursorx-1].mark |= mattr;
  1843.  
  1844.    /* serial/fullrow controls apply to parts of the row */
  1845.    if(mode) {  /* serial || fullrow */
  1846.  
  1847.       /* receiption of serial DBS/DBH in last row of scrolling area        */
  1848.       /* forces a scroll up + a cursor up before writing (page 101) */
  1849.       if( (t.service_break || !(screen[y][0].attr & ATTR_PROTECTED))  &&
  1850.      (a==ATTR_YDOUBLE || a==ATTR_XYDOUBLE) &&
  1851.      t.scroll_area && t.cursory==t.scroll_lower) {
  1852.      scroll(1);
  1853.      move_cursor(APU);
  1854.      y = t.cursory-1;
  1855.       }
  1856.  
  1857.       x = (mode==2) ? 0 : t.cursorx-1;
  1858.  
  1859.       do {
  1860.      refresh = 0;
  1861.  
  1862.      /* fullrow controls delete the marker in the complete row */
  1863.      if(mode==2)  screen[y][x].mark &= ~mattr;
  1864.  
  1865.      if( t.service_break || !(screen[y][x].attr & ATTR_PROTECTED) ||
  1866.         (a==ATTR_PROTECTED && set==0) ) {
  1867.         switch(a) {
  1868.            case ATTR_NODOUBLE:
  1869.               if(screen[y][x].attr & (ATTR_XDOUBLE|ATTR_YDOUBLE))
  1870.              refresh = 1;
  1871.           screen[y][x].attr &= ~(ATTR_XDOUBLE|ATTR_YDOUBLE);
  1872.           break;
  1873.            case ATTR_XYDOUBLE:
  1874.           if((screen[y][x].attr & (ATTR_XDOUBLE|ATTR_YDOUBLE)) !=
  1875.              (ATTR_XDOUBLE|ATTR_YDOUBLE) )    refresh = 1;
  1876.           screen[y][x].attr |= (ATTR_XDOUBLE|ATTR_YDOUBLE);
  1877.           break;
  1878.            case ATTR_XDOUBLE:
  1879.           if((screen[y][x].attr & (ATTR_XDOUBLE|ATTR_YDOUBLE)) !=
  1880.              ATTR_XDOUBLE )  refresh = 1;
  1881.           screen[y][x].attr &= ~ATTR_YDOUBLE;
  1882.           screen[y][x].attr |= ATTR_XDOUBLE;
  1883.           break;
  1884.            case ATTR_YDOUBLE:
  1885.           if((screen[y][x].attr & (ATTR_XDOUBLE|ATTR_YDOUBLE)) !=
  1886.              ATTR_YDOUBLE )  refresh = 1;
  1887.           screen[y][x].attr &= ~ATTR_XDOUBLE;
  1888.           screen[y][x].attr |= ATTR_YDOUBLE;
  1889.           break;
  1890.            case ATTR_FOREGROUND:
  1891.           if(screen[y][x].fg!=col && screen[y][x].chr!=' ') refresh=1;
  1892.           screen[y][x].fg = (UBYTE)col;
  1893.           break;
  1894.            case ATTR_BACKGROUND:
  1895.           if(screen[y][x].bg != col)  refresh = 1;
  1896.           screen[y][x].bg = (UBYTE)col;
  1897.           break;
  1898.  
  1899.            default:
  1900.           if( ((screen[y][x].attr & a)>0) != set )    refresh = 1;
  1901.           if(set)  screen[y][x].attr |= a;
  1902.           else       screen[y][x].attr &= ~a;
  1903.           break;
  1904.         } /* switch */
  1905.  
  1906.         if(refresh)  redrawc(x+1, y+1);
  1907.  
  1908.         /* (DBH/DBS chars must not cross borders of a protected area) */
  1909.         if(a==ATTR_PROTECTED && y && realattr(y, x+1, ATTR_YDOUBLE) &&
  1910.            attrib(y, x+1, a) != attrib(y+1, x+1, a) )  redrawc(x+1, y);
  1911.  
  1912.      } /* if !protected */
  1913.  
  1914.      x++;
  1915.       }         /* while x<40 && (serialmode --> no marker set) */
  1916.       while(x<40  && (mode!=1 || !(screen[y][x].mark & mattr)) );
  1917.    }
  1918.    else {  /* parallel */
  1919.       switch(a) {
  1920.          case ATTR_NODOUBLE:
  1921.             t.par_attr &= ~(ATTR_XDOUBLE|ATTR_YDOUBLE);
  1922.         break;
  1923.      case ATTR_XYDOUBLE:
  1924.         t.par_attr |= (ATTR_XDOUBLE|ATTR_YDOUBLE);
  1925.         break;
  1926.      case ATTR_XDOUBLE:
  1927.         t.par_attr &= ~ATTR_YDOUBLE;
  1928.             t.par_attr |= ATTR_XDOUBLE;
  1929.         break;
  1930.      case ATTR_YDOUBLE:
  1931.         t.par_attr &= ~ATTR_XDOUBLE;
  1932.             t.par_attr |= ATTR_YDOUBLE;
  1933.         break;
  1934.          case ATTR_FOREGROUND:
  1935.         t.par_fg = col;
  1936.         break;
  1937.      case ATTR_BACKGROUND:
  1938.         t.par_bg = col;
  1939.         break;
  1940.      default:
  1941.         if(set)  t.par_attr |= a;
  1942.         else     t.par_attr &= ~a;
  1943.         break;
  1944.       }
  1945.    }
  1946. }
  1947.  
  1948.  
  1949. /*
  1950.  * output character c from current set at current cursor position.
  1951.  */
  1952.  
  1953. void BTXService::output(int c)
  1954. {
  1955.    int xd, yd, set, mattr, x = t.cursorx, y = t.cursory;
  1956.  
  1957.    /* select active character set */
  1958.    if(t.sshift) set = t.G0123L[ t.sshift ];
  1959.    else         set = t.G0123L[ t.leftright[ (c&0x80) >> 7 ] ];
  1960.  
  1961.    if(t.serialmode) {
  1962.       xd = attrib(y, x, ATTR_XDOUBLE);
  1963.       yd = attrib(y, x, ATTR_YDOUBLE);
  1964.  
  1965.       /* update screen memory (if not protected) */
  1966.       if( t.service_break || !attrib(y, x, ATTR_PROTECTED) ) {
  1967.      screen[y-1][x-1].chr = (unsigned short)(c & ~0x80);
  1968.      screen[y-1][x-1].set = (UBYTE)set;
  1969.      redrawc(x, y);
  1970.       }
  1971.    }
  1972.    else {  /* parallel */
  1973.       xd = (t.par_attr & ATTR_XDOUBLE) > 0;
  1974.       yd = (t.par_attr & ATTR_YDOUBLE) > 0;
  1975.       if(y<2)  yd = 0;
  1976.  
  1977.       /* if not protected, (scroll +) update memory */
  1978.       if( t.service_break || !attrib(y, x, ATTR_PROTECTED) ) {
  1979.  
  1980.  
  1981.  
  1982.      /* parallel DBS/DBH chars in first row of scrolling area          */
  1983.      /* force a scroll down + a cursor down before writing (page 101) */
  1984.      if(yd && t.scroll_area && y==t.scroll_upper) {
  1985.         scroll(0);
  1986.         move_cursor(APD);
  1987.         y = t.cursory;
  1988.      }
  1989.  
  1990.      /* update screen memory
  1991.       * if no DBS/DBH in the first row or in the row below a protected area
  1992.       * if no DBS/DBH in the row below a scrolling area (page 99)
  1993.       */
  1994.      if( !(yd && !t.service_break && attrib(y-1, x, ATTR_PROTECTED))  &&
  1995.         !(yd && t.scroll_area && y==t.scroll_lower+1)  ) {
  1996.  
  1997.         /* parallel DBH/DBS chars extent upwards, write in the row above */
  1998.         if(yd) y--;
  1999.  
  2000.         screen[y-1][x-1].chr  = (unsigned short)(c & ~0x80);
  2001.         screen[y-1][x-1].set  = (UBYTE)set;
  2002.         screen[y-1][x-1].fg   = (UBYTE)t.par_fg;
  2003.         screen[y-1][x-1].bg   = (UBYTE)t.par_bg;
  2004.         screen[y-1][x-1].attr = (unsigned short)t.par_attr;
  2005.  
  2006.         /* par. DBS/DBW attrs apply also to the next char ! (page 106) */
  2007.         if(xd && x<40)    screen[y-1][x].attr = (unsigned short)t.par_attr;
  2008.  
  2009.         mattr = t.par_attr & ~ATTR_ANYSIZE;
  2010.         if(t.par_attr & ATTR_ANYSIZE)  mattr |= ATTR_SIZE;
  2011.  
  2012.         if(x>1) {  /* set/reset markers */
  2013.            screen[y-1][x-1].mark = (unsigned short)(screen[y-1][x-1-1].attr ^ mattr);
  2014.            screen[y-1][x-1].mark &= ~(ATTR_FOREGROUND|ATTR_BACKGROUND);
  2015.            if(screen[y-1][x-1-1].fg!=t.par_fg)
  2016.               screen[y-1][x-1].mark |= ATTR_FOREGROUND;
  2017.            if(screen[y-1][x-1-1].bg!=t.par_bg)
  2018.               screen[y-1][x-1].mark |= ATTR_BACKGROUND;
  2019.         }
  2020.         if(x<40) {    /* set/reset markers */
  2021.            screen[y-1][x].mark = (unsigned short)(mattr ^ screen[y-1][x].attr);
  2022.            screen[y-1][x].mark &= ~(ATTR_FOREGROUND|ATTR_BACKGROUND);
  2023.            if(screen[y-1][x].fg!=t.par_fg)
  2024.               screen[y-1][x].mark |= ATTR_FOREGROUND;
  2025.            if(screen[y-1][x].bg!=t.par_bg)
  2026.               screen[y-1][x].mark |= ATTR_BACKGROUND;
  2027.         }
  2028.  
  2029.         redrawc(x, y);
  2030.      } /* scrolling/protected area */
  2031.       } /* if not protected */
  2032.    }  /* if serial / parallel */
  2033.  
  2034.    if(xd && t.cursorx<40)  move_cursor(APF);
  2035.    move_cursor(APF);
  2036.    t.sshift = 0;
  2037. }
  2038.  
  2039.  
  2040. /*
  2041.  * redraws character at screen position x, y (1 based !),
  2042.  * if not concealed or obscured
  2043.  */
  2044.  
  2045. void BTXService::redrawc(int x, int y)
  2046. {
  2047.    int c, set, xd, yd, up_in=0, dn_in=0;
  2048.    unsigned int real, xreal, yreal, xyreal;
  2049.  
  2050.       /* check whether attributes are valid */
  2051.       xd = attrib(y, x, ATTR_XDOUBLE);
  2052.       yd = attrib(y, x, ATTR_YDOUBLE);
  2053.       if(x>=40)    xd = 0;
  2054.       if(y>=rows)  yd = 0;
  2055.  
  2056.       /* check whether origin is obscured */
  2057.       if( (y>1 && realattr(y-1, x, ATTR_YDOUBLE)) ||
  2058.           (x>1 && realattr(y, x-1, ATTR_XDOUBLE)) ||
  2059.       (y>1 && x>1 && realattr(y-1, x-1, ATTR_XDOUBLE) &&
  2060.           realattr(y-1, x-1, ATTR_YDOUBLE)) ) {
  2061.      screen[y-1][x-1].real = 0;
  2062.       }
  2063.       else {
  2064.      /* check whether DBW char is partially obscured */
  2065.      if(xd && y>1 && x<40 && realattr(y-1, x+1, ATTR_YDOUBLE))    xd = 0;
  2066.  
  2067.      /* check whether char crosses borders of scrolling area (page 99) */
  2068.      if(yd && t.scroll_area) {
  2069.         if(y  >=t.scroll_upper && y  <=t.scroll_lower)    up_in=1;
  2070.         if(y+1>=t.scroll_upper && y+1<=t.scroll_lower)    dn_in=1;
  2071.         if(up_in != dn_in)    yd = 0;
  2072.      }
  2073.  
  2074.      /* check whether char crosses borders of protected area (page 110) */
  2075.      if(yd &&  attrib(y, x, ATTR_PROTECTED) !=
  2076.                attrib(y+1, x, ATTR_PROTECTED) )  yd=0;
  2077.  
  2078.      /* concealed characters are drawn as SPACES (page 109) */
  2079.      if(!reveal && attrib(y, x, ATTR_CONCEALED)) { c=' ';    set=PRIM; }
  2080.      else {
  2081.         c    = screen[y-1][x-1].chr & 0x7f;
  2082.         set = screen[y-1][x-1].set;
  2083.      }
  2084.  
  2085.      /* now really display the character in the remaining size */
  2086.      AppDisplay->xputc(c, set, x-1, y-1, xd, yd,
  2087.            attrib(y, x, ATTR_UNDERLINE),
  2088.            (screen[y-1][x-1].chr>>8) & 0x7f,
  2089.            attrib(y, x, ATTR_INVERTED) ? attr_bg(y, x) : attr_fg(y, x),
  2090.            attrib(y, x, ATTR_INVERTED) ? attr_fg(y, x) : attr_bg(y, x) );
  2091.      if(t.cursor_on && x==t.cursorx && y==t.cursory)  AppDisplay->xcursor(x-1, y-1);
  2092.  
  2093.      /* update 'real' attributes */
  2094.      real = screen[y-1][x-1].real;
  2095.      screen[y-1][x-1].real = (unsigned short)(screen[y-1][x-1].attr & ~ATTR_ANYSIZE);
  2096.      if(xd) {
  2097.         screen[y-1][x-1].real |= ATTR_XDOUBLE;
  2098.         xreal = screen[y-1][x].real;
  2099.         screen[y-1][x].real = 0;
  2100.      }
  2101.      if(yd) {
  2102.         screen[y-1][x-1].real |= ATTR_YDOUBLE;
  2103.         yreal = screen[y][x-1].real;
  2104.         screen[y][x-1].real = 0;
  2105.      }
  2106.      if(xd && yd) {
  2107.         xyreal = screen[y][x].real;
  2108.         screen[y][x].real = 0;
  2109.      }
  2110.  
  2111.      /* redraw (indirect recursion !!) neighbours */
  2112.      updatec(real, x, y);
  2113.      if(xd)  updatec(xreal, x+1, y);
  2114.      if(yd)  updatec(yreal, x, y+1);
  2115.      if(xd && yd)  updatec(xyreal, x+1, y+1);
  2116.  
  2117.      /* redraw an enlarged char to the left (now partially obscured !) */
  2118.      if(yd && x>1 && realattr(y+1, x-1, ATTR_XDOUBLE))    redrawc(x-1, y+1);
  2119.       } /* origin obscured */
  2120. }
  2121.  
  2122.  
  2123. /*
  2124.  * this character has been obscured. check whether it was an enlarged char
  2125.  * and therefor its neighbours have to be redrawn.
  2126.  */
  2127. void BTXService::updatec(int real, int x, int y)
  2128. {
  2129.    if(real & ATTR_XDOUBLE)    redrawc(x+1, y);
  2130.    if(real & ATTR_YDOUBLE)    redrawc(x, y+1);
  2131.    if( (real & ATTR_XDOUBLE) && (real & ATTR_YDOUBLE) )  redrawc(x+1, y+1);
  2132. }
  2133.  
  2134.  
  2135. /*
  2136.  * redraw rectangle of screen (for exposure handling)
  2137.  */
  2138.  
  2139.  
  2140. void BTXService::redraw_screen_rect(int x1, int y1, int x2, int y2)
  2141. {
  2142.    int x, y;
  2143.  
  2144.    for(y=y1; y<=y2; y++)
  2145.       for(x=x1; x<=x2; x++)  redrawc(x+1, y+1);
  2146. }
  2147.  
  2148.  
  2149. /*
  2150.  * DRC's in the range start-stop with step have been (re)defined.
  2151.  * This routine checks whether this character is currently visible and so
  2152.  * needs to be redisplayed.
  2153.  */
  2154.  
  2155. void BTXService::update_DRCS_display(int start, int stop, int step)
  2156. {
  2157.    int x, y, c;
  2158.  
  2159.    for(y=0; y<24; y++)
  2160.       for(x=0; x<40; x++)
  2161.      if(screen[y][x].set==DRCS)
  2162.         for(c=start; c<stop; c+=step)
  2163.            if(screen[y][x].chr==c)    redrawc(x+1, y+1);
  2164. }
  2165.  
  2166.  
  2167. /*
  2168.  * initialize screen memory and clear display
  2169.  */
  2170.  
  2171. void BTXService::clearscreen()
  2172. {
  2173.    int x, y;
  2174.  
  2175.    t.clut = 0;
  2176.    t.par_attr = 0;
  2177.    t.par_fg = WHITE;
  2178.    t.par_bg = TRANSPARENT;
  2179.    t.scroll_area = 0;
  2180.    t.scroll_impl = 1;
  2181.    t.cursorx = t.cursory = 1;
  2182.  
  2183.    for(y=0; y<24; y++)
  2184.       for(x=0; x<40; x++) {
  2185.      screen[y][x].chr = ' ';
  2186.      screen[y][x].set = PRIM;
  2187.      screen[y][x].attr = 0;
  2188.      screen[y][x].real = 0;
  2189.      screen[y][x].mark = 0;
  2190.      screen[y][x].fg = WHITE;
  2191.      screen[y][x].bg = TRANSPARENT;
  2192.       }
  2193.  
  2194.    AppDisplay->xclearscreen();
  2195.    if(t.cursor_on) AppDisplay->xcursor(0, 0);
  2196. }
  2197.  
  2198. void BTXService::scroll(int up)
  2199. {
  2200.    int y, x, savereal[40];
  2201.  
  2202.    if(up) {
  2203.       /* save real attributes of first row */
  2204.       for(x=0; x<40; x++)  savereal[x] = screen[t.scroll_upper-1][x].real;
  2205.  
  2206.       /* scroll screen memory up */
  2207.       for(y=t.scroll_upper-1; y<t.scroll_lower-1; y++) {
  2208.      for(x=0; x<40; x++)  screen[y][x] = screen[y+1][x];
  2209.       }
  2210.    }
  2211.    else {
  2212.       /* scroll screen memory down */
  2213.       for(y=t.scroll_lower-1; y>t.scroll_upper-1; y--) {
  2214.      for(x=0; x<40; x++)  screen[y][x] = screen[y-1][x];
  2215.       }
  2216.    }
  2217.  
  2218.    /* clear row */
  2219.    for(x=0; x<40; x++) {
  2220.       screen[y][x].chr = ' ';
  2221.       screen[y][x].set = PRIM;
  2222.       screen[y][x].attr = 0;
  2223.       screen[y][x].real = 0;
  2224.       screen[y][x].mark = 0;
  2225.       screen[y][x].fg = WHITE;
  2226.       screen[y][x].bg = TRANSPARENT;
  2227.    }
  2228.  
  2229.    /* fast scroll the area */
  2230.    for(y=t.scroll_upper; y<=t.scroll_lower; y++)
  2231.       for(x=1; x<=40; x++)    redrawc(x, y);
  2232.  
  2233.    /* redraw cursor */
  2234.    if(t.cursor_on && t.cursory>=t.scroll_upper && t.cursory<=t.scroll_lower)
  2235.       AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
  2236. }
  2237.  
  2238. void BTXService::do_Telesoftware(void)
  2239. {
  2240.     int c,i,j,len,total,size,temp;
  2241.     UBYTE *data,*final;
  2242.  
  2243.     c = layer2getc();
  2244.  
  2245.     if(reachedEOF)
  2246.         return;
  2247.  
  2248.     switch(c)
  2249.     {
  2250.         case 0x27:            // D-Set mode, A7.4, p5
  2251.  
  2252.             for(i = 0 ; i < 4 ; i++)
  2253.                 layer2getc();
  2254.  
  2255.             c = layer2getc();
  2256.  
  2257.             if(reachedEOF)
  2258.                 return;
  2259.  
  2260.             telemode = MODE_Unknown;
  2261.  
  2262.             if(c == 0x42)
  2263.                 telemode = MODE_3in4;
  2264.  
  2265.             if(c == 0x41)
  2266.                 telemode = MODE_8Bit;
  2267.  
  2268.             telesequence = 0x41;
  2269.  
  2270.             D(printf("d-set mode, mode = %ld\n",telemode));
  2271.  
  2272.             break;
  2273.  
  2274.         case 0x33:            // D-End group, A7.4, p6
  2275.  
  2276.             D(printf("d-end group\n"));
  2277.  
  2278.             if(telefile)
  2279.             {
  2280.                 fclose(telefile);
  2281.                 telefile = NULL;
  2282.             }
  2283.  
  2284.             is_fif = FALSE;
  2285.  
  2286.             telemode = MODE_Unknown;
  2287.  
  2288.             teledownload = FALSE;
  2289.  
  2290.             telename[0] = 0;
  2291.  
  2292.             break;
  2293.  
  2294.         default:            // D-Data, A7.4, p3
  2295.  
  2296.             telesequence = c;
  2297.  
  2298.             D(printf("sequence code 0x%02lx\n",c));
  2299.  
  2300.             total = 0;
  2301.  
  2302.             for(;;)
  2303.             {
  2304.                 c = layer2getc();
  2305.  
  2306.                 if(reachedEOF)
  2307.                     return;
  2308.                 else
  2309.                 {
  2310.                     if(c == US)
  2311.                     {
  2312.                         if(telemode == MODE_8Bit)    // If in 8-bit mode, take a
  2313.                         {                            // look at the next character
  2314.                             int c1 = layer2getc();
  2315.  
  2316.                                 // If it's another US, just stuff
  2317.                                 // the other US into the buffer and
  2318.                                 // continue. Otherwise, it's the
  2319.                                 // end of this VPDE
  2320.  
  2321.                             if(c1 != US)
  2322.                             {
  2323.                                 layer2ungetc(c1);    // Note: lifo order
  2324.                                 layer2ungetc(US);
  2325.                                 break;
  2326.                             }    // Note: else case falls through down here
  2327.                         }
  2328.                         else
  2329.                         {
  2330.                             layer2ungetc(US);
  2331.                             break;
  2332.                         }
  2333.                     }
  2334.  
  2335.                     telebuffer[total++] = (UBYTE)c;
  2336.                 }
  2337.             }
  2338.  
  2339.             if(telemode == MODE_3in4)
  2340.                 len = decode_3in4(telebuffer,telebuffer,total);
  2341.  
  2342.             data = telebuffer;
  2343.  
  2344.             while(len > 0)
  2345.             {
  2346.                 switch(*data)
  2347.                 {
  2348.                     case 0x23:            // T-Associate, A7.4, p7
  2349.  
  2350.                         len--;
  2351.                         data++;
  2352.  
  2353.                         D(printf("t-associate\n"));
  2354.  
  2355.                         teledownload = TRUE;
  2356.  
  2357.                         len--;
  2358.                         size = *data++;
  2359.  
  2360.                         len -= size;
  2361.                         data += size;
  2362.  
  2363.                         break;
  2364.  
  2365.                     case 0x63:            // T-Filespec, A7.4, p9
  2366.  
  2367.                         len--;
  2368.                         data++;
  2369.  
  2370.                         D(printf("t-filespec\n"));
  2371.  
  2372.                         len--;
  2373.                         size = *data++;
  2374.                         final = data + size;
  2375.                         len -= size;
  2376.  
  2377.                         data++;
  2378.                         size--;
  2379.  
  2380.                         while(size > 0)
  2381.                         {
  2382.                             c = *data++;
  2383.                             size--;
  2384.  
  2385.                             switch(c)
  2386.                             {
  2387.                                 case 0x65:        // Filename
  2388.  
  2389.                                     total = *data++;
  2390.                                     size--;
  2391.  
  2392.                                     for(j = 0 ; j < total ; j++)
  2393.                                     {
  2394.                                         telename[j] = (char)*data++;
  2395.                                         size--;
  2396.                                     }
  2397.  
  2398.                                     telename[j] = 0;
  2399.  
  2400.                                     D(printf("filename |%s|\n",telename));
  2401.  
  2402.                                     break;
  2403.  
  2404.                                 case 0x7F:        // Date/time
  2405.  
  2406.                                     total = *data++;
  2407.                                     size--;
  2408.  
  2409.                                     for(j = 0 ; j < total ; j++)
  2410.                                     {
  2411.                                         teledate[j] = (char)*data++;
  2412.                                         size--;
  2413.                                     }
  2414.  
  2415.                                     teledate[j] = 0;
  2416.  
  2417.                                     D(printf("date |%s|\n",teledate));
  2418.  
  2419.                                     break;
  2420.  
  2421.                                 case 0x67:        // File length
  2422.  
  2423.                                     total = *data++;
  2424.                                     size--;
  2425.  
  2426.                                     temp = 0;
  2427.  
  2428.                                     for(j = 0 ; j < total ; j++)
  2429.                                     {
  2430.                                         temp = (temp * 256) + (*data++);
  2431.                                         size--;
  2432.                                     }
  2433.  
  2434.                                     telesize = temp;
  2435.  
  2436.                                     D(printf("size %ld\n",temp));
  2437.  
  2438.                                     break;
  2439.  
  2440.                                 default:        // Whatever...
  2441.  
  2442.                                     total = *data++;
  2443.                                     size--;
  2444.  
  2445.                                     data += total;
  2446.                                     size -= total;
  2447.                                     break;
  2448.                             }
  2449.                         }
  2450.  
  2451.                         data = final;
  2452.  
  2453.                         break;
  2454.  
  2455.                     case 0x43:    // T-Write-Start, A7.4, p10
  2456.  
  2457.                         len--;
  2458.                         data++;
  2459.  
  2460.                         D(printf("t-write-start\n"));
  2461.  
  2462.                         len--;
  2463.                         size = *data++;
  2464.  
  2465.                         len -= size;
  2466.                         data += size;
  2467.  
  2468.                         if(telefile)
  2469.                         {
  2470.                             fclose(telefile);
  2471.                             telefile = NULL;
  2472.                         }
  2473.  
  2474.                         is_fif = FALSE;
  2475.  
  2476.                         if(!telefile && teledownload)
  2477.                         {
  2478.                             if(telename[0])
  2479.                                 telefile = fopen((const char *)telename,"wb");
  2480.                             else
  2481.                                 telefile = fopen((const char *)"telesoftware","wb");
  2482.                         }
  2483.  
  2484.                         if(len)
  2485.                         {
  2486.                             D(printf("\t%ld bytes in this block\n",len));
  2487.  
  2488.                             if(telefile)
  2489.                             {
  2490.                                 if(fwrite(data,len,1,telefile) != 1)
  2491.                                     return;
  2492.                             }
  2493.  
  2494.                             len = 0;
  2495.                         }
  2496.  
  2497.                         break;
  2498.  
  2499.                     case 0x45:    // T-Write, A7.4, p11
  2500.  
  2501.                         len--;
  2502.                         data++;
  2503.  
  2504.                         D(printf("t-write\n"));
  2505.  
  2506.                         len--;
  2507.                         size = *data++;
  2508.  
  2509.                         len -= size;
  2510.                         data += size;
  2511.  
  2512.                         if(len)
  2513.                         {
  2514.                             D(printf("\t%ld bytes in this block\n",len));
  2515.  
  2516.                             if(telefile)
  2517.                             {
  2518.                                 if(fwrite(data,len,1,telefile) != 1)
  2519.                                     return;
  2520.                             }
  2521.  
  2522.                             len = 0;
  2523.                         }
  2524.  
  2525.                         break;
  2526.  
  2527.                     case 0x47:    // T-Write-End, A7.4, p11
  2528.  
  2529.                         len--;
  2530.                         data++;
  2531.  
  2532.                         D(printf("t-write-end\n"));
  2533.  
  2534.                         len--;
  2535.                         size = *data++;
  2536.  
  2537.                         len -= size;
  2538.                         data += size;
  2539.  
  2540.                         if(len)
  2541.                         {
  2542.                             D(printf("\t%ld bytes in this block\n",len));
  2543.  
  2544.                             if(telefile)
  2545.                             {
  2546.                                 if(fwrite(data,len,1,telefile) != 1)
  2547.                                     return;
  2548.                             }
  2549.  
  2550.                             len = 0;
  2551.                         }
  2552.  
  2553.                         if(telefile)
  2554.                         {
  2555.                             fclose(telefile);
  2556.                             telefile = NULL;
  2557.                         }
  2558.  
  2559.                         is_fif = FALSE;
  2560.  
  2561.                         break;
  2562.  
  2563.                     default:
  2564.  
  2565.                         D(printf("unknown sequence 0x%02lx\n",c));
  2566.  
  2567.                         len--;
  2568.                         data++;
  2569.  
  2570.                         len--;
  2571.                         size = *data++;
  2572.  
  2573.                         len -= size;
  2574.                         data += size;
  2575.  
  2576.                         break;
  2577.                 }
  2578.             }
  2579.  
  2580.             break;
  2581.     }
  2582. }
  2583.  
  2584.     // decode 3-in-4 encoded data into eight bit data
  2585.  
  2586. int BTXService::decode_3in4(const UBYTE *data,UBYTE *out,int total)
  2587. {
  2588.     int len,eaten,done = 0;
  2589.     UBYTE buf[4];
  2590.  
  2591.     while(total > 0)
  2592.     {
  2593.         if(total == 2)
  2594.         {
  2595.             buf[0] = (UBYTE)(((data[0] & 0x30) << 2) | (data[1] & 0x3f));
  2596.             len = 1;
  2597.             eaten = 2;
  2598.         }
  2599.         else
  2600.         {
  2601.             if(total == 3)
  2602.             {
  2603.                 buf[0] = (UBYTE)(((data[0] & 0x30) << 2) | (data[1] & 0x3f));
  2604.                 buf[1] = (UBYTE)(((data[0] & 0x0c) << 4) | (data[2] & 0x3f));
  2605.                 len = 2;
  2606.                 eaten = 3;
  2607.             }
  2608.             else
  2609.             {
  2610.                 if(total >= 4)
  2611.                 {
  2612.                     buf[0] = (UBYTE)(((data[0] & 0x30) << 2) | (data[1] & 0x3f));
  2613.                     buf[1] = (UBYTE)(((data[0] & 0x0c) << 4) | (data[2] & 0x3f));
  2614.                     buf[2] = (UBYTE)(((data[0] & 0x03) << 6) | (data[3] & 0x3f));
  2615.                     len = 3;
  2616.                     eaten = 4;
  2617.                 }
  2618.                 else
  2619.                     break;
  2620.             }
  2621.         }
  2622.  
  2623.         memcpy(out,buf,len);
  2624.  
  2625.         total -= eaten;
  2626.         data += eaten;
  2627.  
  2628.         out += len;
  2629.         done += len;
  2630.     }
  2631.  
  2632.     return(done);
  2633. }
  2634.  
  2635.     // process incoming transparent data, stores the data
  2636.     // in the transparent_buffer[..] for later processing.
  2637.     // transparent_collected holds the number of bytes
  2638.     // stored in the buffer
  2639.  
  2640. void BTXService::do_TransparentData(void)
  2641. {
  2642.     int c;
  2643.  
  2644.     while(transparent_max > 0)
  2645.     {
  2646.             // Grab the next byte
  2647.  
  2648.         c = layer2getc();
  2649.  
  2650.         if(reachedEOF)
  2651.             break;
  2652.  
  2653.             // Is this another US?
  2654.  
  2655.         if(c == US)
  2656.         {
  2657.             int c1;
  2658.  
  2659.                 // Check the next byte
  2660.  
  2661.             c1 = layer2getc();
  2662.  
  2663.             if(reachedEOF)
  2664.                 break;
  2665.  
  2666.                 // If it's another US, store it and continue
  2667.  
  2668.             if(c1 == US)
  2669.             {
  2670.                 transparent_buffer[transparent_collected++] = US;
  2671.                 transparent_max--;
  2672.             }
  2673.             else
  2674.             {
  2675.                     // It's a nested VPDE...
  2676.  
  2677.                 layer2ungetc(c1);    // Note: lifo order
  2678.                 layer2ungetc(US);
  2679.                 break;
  2680.             }
  2681.         }
  2682.         else
  2683.         {
  2684.             transparent_buffer[transparent_collected++] = US;
  2685.             transparent_max--;
  2686.         }
  2687.     }
  2688. }
  2689.  
  2690.     // process incoming data in FIF format.
  2691.  
  2692. void BTXService::do_FIF(void)
  2693. {
  2694.     int c,headerlen,datalen,len,i,j;
  2695.     UWORD crc;
  2696.  
  2697.         // Introducer is <US> 0x29 0x51
  2698.  
  2699.     c = layer2getc();
  2700.  
  2701.     if(reachedEOF || c != 0x51)
  2702.         return;
  2703.  
  2704.         // header length (two bytes)
  2705.  
  2706.     headerlen = layer2getc() * 256 + layer2getc();
  2707.  
  2708.     if(reachedEOF)
  2709.         return;
  2710.  
  2711.         // data length (two bytes)
  2712.  
  2713.     datalen = layer2getc() * 256 + layer2getc();
  2714.  
  2715.     if(reachedEOF)
  2716.         return;
  2717.  
  2718.         // Read the header
  2719.  
  2720.     for(i = 0 ; i < headerlen ; i++)
  2721.     {
  2722.         c = layer2getc();
  2723.  
  2724.         if(reachedEOF)
  2725.             return;
  2726.         else
  2727.             telebuffer[i] = (unsigned char)c;
  2728.     }
  2729.  
  2730.         // Are we doing a file transfer?
  2731.  
  2732.     if(!is_fif)
  2733.         compressionMode = 0;
  2734.  
  2735.     for(i = 0 ; i < headerlen ; )
  2736.     {
  2737.         switch(telebuffer[i++])
  2738.         {
  2739.                 // filename
  2740.  
  2741.             case 0x23:
  2742.  
  2743.                 len = telebuffer[i++];
  2744.  
  2745.                 for(j = 0 ; j < len ; j++)
  2746.                     fileName[j] = (char)telebuffer[i++];
  2747.  
  2748.                 fileName[j] = 0;
  2749.  
  2750.                 D(printf("\tfileName |%s|\n",fileName));
  2751.                 break;
  2752.  
  2753.                 // date/time
  2754.  
  2755.             case 0x24:
  2756.  
  2757.                 len = telebuffer[i++];
  2758.  
  2759.                 for(j = 0 ; j < len ; j++)
  2760.                     dateTime[j] = (char)telebuffer[i++];
  2761.  
  2762.                 dateTime[j] = 0;
  2763.  
  2764.                 D(printf("\tdateTime |%s|\n",dateTime));
  2765.                 break;
  2766.  
  2767.                 // file length
  2768.  
  2769.             case 0x25:
  2770.  
  2771.                 len = telebuffer[i++];
  2772.  
  2773.                 for(j = 0, fileLength = 0 ; j < len ; j++)
  2774.                     fileLength = 256 * fileLength + telebuffer[i++];
  2775.  
  2776.                 D(printf("\tfileLength %ld\n",fileLength));
  2777.                 break;
  2778.  
  2779.                 // file coding
  2780.  
  2781.             case 0x27:
  2782.  
  2783.                 len = telebuffer[i++];
  2784.  
  2785.                 if(len)
  2786.                 {
  2787.                     fileCoding = telebuffer[i++];
  2788.                     len--;
  2789.  
  2790.                     for(j = 0 ; j < len ; j++)
  2791.                         codingString[j] = (char)telebuffer[i++];
  2792.  
  2793.                     codingString[j] = 0;
  2794.  
  2795.                     D(printf("\tfileCoding %ld string |%s|\n",fileCoding,codingString));
  2796.                 }
  2797.  
  2798.                 break;
  2799.  
  2800.                 // destination name
  2801.  
  2802.             case 0x28:
  2803.  
  2804.                 len = telebuffer[i++];
  2805.  
  2806.                 for(j = 0 ; j < len ; j++)
  2807.                     destinationName[j] = (char)telebuffer[i++];
  2808.  
  2809.                 destinationName[j] = 0;
  2810.  
  2811.                 D(printf("\tdestinationName |%s|\n",destinationName));
  2812.                 break;
  2813.  
  2814.                 // user field
  2815.  
  2816.             case 0x2a:
  2817.  
  2818.                 len = telebuffer[i++];
  2819.  
  2820.                 for(j = 0 ; j < len ; j++)
  2821.                     userField[j] = (char)telebuffer[i++];
  2822.  
  2823.                 userField[j] = 0;
  2824.  
  2825.                 D(printf("\tuserField |%s|\n",userField));
  2826.                 break;
  2827.  
  2828.                 // compression mode
  2829.  
  2830.             case 0x2e:
  2831.  
  2832.                 len = telebuffer[i++];
  2833.                 compressionMode = telebuffer[i++];
  2834.  
  2835.                 D(printf("\tcompressionMode %ld\n",compressionMode));
  2836.                 break;
  2837.  
  2838.                 // file checksum
  2839.  
  2840.             case 0x30:
  2841.  
  2842.                 len = telebuffer[i++];
  2843.  
  2844.                 for(j = 0, fileChecksum = 0 ; j < len ; j++)
  2845.                     fileChecksum = 256 * fileChecksum + telebuffer[i++];
  2846.  
  2847.                 D(printf("\tfileChecksum 0x%08lx\n",fileChecksum));
  2848.                 break;
  2849.  
  2850.                 // transferid, timestamp and CRC
  2851.  
  2852.             case 0x80:
  2853.  
  2854.                 len = telebuffer[i++];
  2855.  
  2856.                 for(j = 0, transferTimeStamp = 0 ; j < 2 ; j++)
  2857.                     transferTimeStamp = 256 * transferTimeStamp + telebuffer[i++];
  2858.  
  2859.                 for(j = 0, transferID = 0 ; j < 2 ; j++)
  2860.                     transferID = (UWORD)(256 * transferID + telebuffer[i++]);
  2861.  
  2862.                 D(printf("\ttransferTimeStamp %ld\n\ttransferID 0x%02lx\n",transferTimeStamp,transferID));
  2863.                 break;
  2864.  
  2865.                 // block number
  2866.  
  2867.             case 0x81:
  2868.  
  2869.                 len = telebuffer[i++];
  2870.  
  2871.                 for(j = 0, blockNumber = 0 ; j < len ; j++)
  2872.                     blockNumber = 256 * blockNumber + telebuffer[i++];
  2873.  
  2874.                 D(printf("\tblockNumber %ld\n",blockNumber));
  2875.                 break;
  2876.  
  2877.                 // number of blocks
  2878.  
  2879.             case 0x82:
  2880.  
  2881.                 len = telebuffer[i++];
  2882.  
  2883.                 for(j = 0, numberOfBlocks = 0 ; j < len ; j++)
  2884.                     numberOfBlocks = 256 * numberOfBlocks + telebuffer[i++];
  2885.  
  2886.                 D(printf("\tnumberOfBlocks %ld\n",numberOfBlocks));
  2887.                 break;
  2888.  
  2889.                 // restart code
  2890.  
  2891.             case 0x83:
  2892.  
  2893.                 restartLen = telebuffer[i++];
  2894.  
  2895.                 for(j = 0 ; j < restartLen ; j++)
  2896.                     restartCode[j] = (char)telebuffer[i++];
  2897.  
  2898.                 restartCode[j] = 0;
  2899. #if 0 D(+1)
  2900.                 printf("\trestartCode >");
  2901.  
  2902.                 for(j = 0 ; j < restartLen ; j++)
  2903.                 {
  2904.                     if(restartCode[j] < ' ')
  2905.                         printf("^%lc ",restartCode[j] + '@');
  2906.                     else
  2907.                     {
  2908.                         if(restartCode[j] >= 127 && restartCode[j] < 160)
  2909.                             printf("0x%02lx ",restartCode[j]);
  2910.                         else
  2911.                             printf("|%lc| ",restartCode[j]);
  2912.                     }
  2913.                 }
  2914.  
  2915.                 printf("<\n\t\tlen %ld\n",restartLen);
  2916. #endif
  2917.                 break;
  2918.  
  2919.                 // continue code
  2920.  
  2921.             case 0x84:
  2922.  
  2923.                 continueLen = telebuffer[i++];
  2924.  
  2925.                 for(j = 0 ; j < continueLen ; j++)
  2926.                     continueCode[j] = (char)telebuffer[i++];
  2927.  
  2928.                 continueCode[j] = 0;
  2929. #if 0 D(+1)
  2930.                 printf("\tcontinueCode >");
  2931.  
  2932.                 for(j = 0 ; j < continueLen ; j++)
  2933.                 {
  2934.                     if(continueCode[j] < ' ')
  2935.                         printf("^%lc ",continueCode[j] + '@');
  2936.                     else
  2937.                     {
  2938.                         if(continueCode[j] >= 127 && continueCode[j] < 160)
  2939.                             printf("0x%02lx ",continueCode[j]);
  2940.                         else
  2941.                             printf("|%lc| ",continueCode[j]);
  2942.                     }
  2943.                 }
  2944.  
  2945.                 printf("<\n\t\tlen %ld\n",continueLen);
  2946. #endif
  2947.                 break;
  2948.  
  2949.                 // block checksum
  2950.  
  2951.             case 0x85:
  2952.  
  2953.                 len = telebuffer[i++];
  2954.  
  2955.                 for(j = 0, blockChecksum = 0 ; j < len ; j++)
  2956.                     blockChecksum = (UWORD)(256 * blockChecksum + telebuffer[i++]);
  2957.  
  2958.                 D(printf("\tblockChecksum 0x%02lx\n",blockChecksum));
  2959.                 break;
  2960.         }
  2961.     }
  2962.  
  2963.     if(!telefile && fileName[0])
  2964.     {
  2965.         char *name;
  2966.  
  2967.         if(compressionMode == 0x4f || compressionMode == 0x40)
  2968.             name = "tempfif";
  2969.         else
  2970.             name = fileName;
  2971.  
  2972.         if(telefile = fopen(name,"wb"))
  2973.             is_fif = TRUE;
  2974.     }
  2975.  
  2976.     D(printf("\t-> %ld bytes of data in this block\n",datalen));
  2977.  
  2978.         // Read the data
  2979.  
  2980.     crc = 0;
  2981.  
  2982.     for(i = 0 ; i < datalen ; i++)
  2983.     {
  2984.         c = layer2getc();
  2985.  
  2986.         if(reachedEOF)
  2987.             return;
  2988.         else
  2989.         {
  2990.             telebuffer[i] = (unsigned char)c;
  2991.  
  2992.             for(j = 0 ; j < 8 ; j++)
  2993.             {
  2994.                 if((crc & 1) ^ (c & 1))
  2995.                     crc = (UWORD)((crc >> 1) ^ 0xa001);
  2996.                 else
  2997.                     crc = (UWORD)(crc >> 1);
  2998.  
  2999.                 c = c >> 1;
  3000.             }
  3001.         }
  3002.     }
  3003.  
  3004.     if(crc != blockChecksum)
  3005.         D(printf("crc error  here=%02lx there=%02lx\n",crc,blockChecksum));
  3006.  
  3007.     if(telefile && datalen && crc == blockChecksum)
  3008.         fwrite(telebuffer,datalen,1,telefile);
  3009.  
  3010.         // In case of error, request this block to be resent
  3011.  
  3012.     if(crc != blockChecksum)
  3013.     {
  3014.         if(restartLen > 0)
  3015.             write((STRPTR)restartCode,restartLen);
  3016.     }
  3017.     else
  3018.     {
  3019.             // request the next block, if there is any
  3020.  
  3021.         if(blockNumber < numberOfBlocks)
  3022.         {
  3023.             if(continueLen > 0)
  3024.                 write((STRPTR)continueCode,continueLen);
  3025.         }
  3026.         else
  3027.         {
  3028.             if(telefile)
  3029.             {
  3030.                 fclose(telefile);
  3031.                 telefile = NULL;
  3032.  
  3033.                 if(compressionMode == 0x4f || compressionMode == 0x40)
  3034.                 {
  3035.                     FILE *in,*out;
  3036.  
  3037.                     if(in = fopen("tempfif","rb"))
  3038.                     {
  3039.                         if(out = fopen(fileName,"wb"))
  3040.                         {
  3041.                             ULONG crc;
  3042.  
  3043.                             if(compressionMode == 0x4f)
  3044.                                 LZH_Decode(in, out, fileLength, &crc);
  3045.                             else
  3046.                                 RLE_Decode(in, out, fileLength, &crc);
  3047.  
  3048.                             fclose(out);
  3049.                         }
  3050.  
  3051.                         fclose(in);
  3052.                     }
  3053.  
  3054.                     unlink("tempfif");
  3055.                 }
  3056.             }
  3057.  
  3058.             is_fif = FALSE;
  3059.         }
  3060.     }
  3061. }
  3062.